Compare commits

..

1 Commits

Author SHA1 Message Date
fc0f3157ea Kernel/LibC: Use builtin functions over inline asm
Getting flags and saving/restoring sse state and reading TSC can be done
using compiler builtins
2026-01-09 15:30:04 +02:00
301 changed files with 4611 additions and 11162 deletions

1
.gitignore vendored
View File

@@ -3,4 +3,3 @@
build/ build/
base/ base/
script/fakeroot-context script/fakeroot-context
tools/update-image-perms

View File

@@ -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,"\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\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\n"); \
fflush(stddbg); \ fflush(stddbg); \
funlockfile(stddbg); \
} while(false) } while(false)
#define dprintln_if(cond, ...) \ #define dprintln_if(cond, ...) \

View File

@@ -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;

View File

@@ -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__)

View File

@@ -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;
} }
@@ -65,20 +66,25 @@ namespace BAN::Math
return (x & (x - 1)) == 0; return (x & (x - 1)) == 0;
} }
template<integral T> template<BAN::integral T>
__attribute__((always_inline)) static constexpr bool will_multiplication_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 false;
if ((a > 0) == (b > 0))
return a > BAN::numeric_limits<T>::max() / b;
else
return a < BAN::numeric_limits<T>::min() / b;
} }
template<integral T> template<BAN::integral T>
__attribute__((always_inline)) static constexpr bool will_addition_overflow(T a, T b)
inline constexpr bool will_addition_overflow(T a, T b)
{ {
T dummy; if (a > 0 && b > 0)
return __builtin_add_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;
return false;
} }
template<typename T> template<typename T>
@@ -92,19 +98,6 @@ namespace BAN::Math
return sizeof(T) * 8 - __builtin_clzll(x) - 1; return sizeof(T) * 8 - __builtin_clzll(x) - 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> template<floating_point T>
inline constexpr T floor(T x) inline constexpr T floor(T x)
{ {
@@ -166,23 +159,7 @@ namespace BAN::Math
"jne 1b;" "jne 1b;"
: "+t"(a) : "+t"(a)
: "u"(b) : "u"(b)
: "ax", "cc" : "ax"
);
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; return a;
} }
@@ -190,7 +167,7 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
static T modf(T x, T* iptr) static T modf(T x, T* iptr)
{ {
const T frac = BAN::Math::fmod<T>(x, (T)1.0); const T frac = BAN::Math::fmod<T>(x, 1);
*iptr = x - frac; *iptr = x - frac;
return frac; return frac;
} }
@@ -198,15 +175,15 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
inline constexpr T frexp(T num, int* exp) inline constexpr T frexp(T num, int* exp)
{ {
if (num == (T)0.0) if (num == 0.0)
{ {
*exp = 0; *exp = 0;
return (T)0.0; return 0.0;
} }
T e; T _exp;
asm("fxtract" : "+t"(num), "=u"(e)); asm("fxtract" : "+t"(num), "=u"(_exp));
*exp = (int)e + 1; *exp = (int)_exp + 1;
return num / (T)2.0; return num / (T)2.0;
} }
@@ -274,7 +251,6 @@ namespace BAN::Math
"fstp %%st(1);" "fstp %%st(1);"
: "+t"(x) : "+t"(x)
); );
return x; return x;
} }
@@ -287,9 +263,18 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
inline constexpr T pow(T x, T y) inline constexpr T pow(T x, T y)
{ {
if (x == (T)0.0) asm(
return (T)0.0; "fyl2x;"
return exp2<T>(y * log2<T>(x)); "fld1;"
"fld %%st(1);"
"fprem;"
"f2xm1;"
"faddp;"
"fscale;"
: "+t"(x), "+u"(y)
);
return x;
} }
template<floating_point T> template<floating_point T>
@@ -325,27 +310,16 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
inline constexpr T sqrt(T x) inline constexpr T sqrt(T x)
{ {
if constexpr(BAN::is_same_v<T, float>) asm("fsqrt" : "+t"(x));
{ return x;
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> template<floating_point T>
inline constexpr T cbrt(T value) inline constexpr T cbrt(T value)
{ {
return pow<T>(value, (T)1.0 / (T)3.0); if (value == 0.0)
return 0.0;
return pow<T>(value, 1.0 / 3.0);
} }
template<floating_point T> template<floating_point T>
@@ -372,21 +346,30 @@ namespace BAN::Math
inline constexpr T tan(T x) inline constexpr T tan(T x)
{ {
T one, ret; T one, ret;
asm("fptan" : "=t"(one), "=u"(ret) : "0"(x)); asm(
"fptan"
: "=t"(one), "=u"(ret)
: "0"(x)
);
return ret; return ret;
} }
template<floating_point T> template<floating_point T>
inline constexpr T atan2(T y, T x) inline constexpr T atan2(T y, T x)
{ {
asm("fpatan" : "+t"(x) : "u"(y) : "st(1)"); asm(
"fpatan"
: "+t"(x)
: "u"(y)
: "st(1)"
);
return x; return x;
} }
template<floating_point T> template<floating_point T>
inline constexpr T atan(T x) inline constexpr T atan(T x)
{ {
return atan2<T>(x, (T)1.0); return atan2<T>(x, 1.0);
} }
template<floating_point T> template<floating_point T>
@@ -395,10 +378,10 @@ namespace BAN::Math
if (x == (T)0.0) if (x == (T)0.0)
return (T)0.0; return (T)0.0;
if (x == (T)1.0) if (x == (T)1.0)
return +numbers::pi_v<T> / (T)2.0; return numbers::pi_v<T> / (T)2.0;
if (x == (T)-1.0) if (x == (T)-1.0)
return -numbers::pi_v<T> / (T)2.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))); return (T)2.0 * atan<T>(x / (T(1.0) + sqrt<T>((T)1.0 - x * x)));
} }
template<floating_point T> template<floating_point T>
@@ -428,7 +411,7 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
inline constexpr T tanh(T x) inline constexpr T tanh(T x)
{ {
const T exp_px = exp<T>(+x); const T exp_px = exp<T>(x);
const T exp_nx = exp<T>(-x); const T exp_nx = exp<T>(-x);
return (exp_px - exp_nx) / (exp_px + exp_nx); return (exp_px - exp_nx) / (exp_px + exp_nx);
} }
@@ -457,9 +440,4 @@ namespace BAN::Math
return sqrt<T>(x * x + y * y); return sqrt<T>(x * x + y * y);
} }
#ifdef BAN_MATH_POP_OPTIONS
#undef BAN_MATH_POP_OPTIONS
#pragma GCC pop_options
#endif
} }

View File

@@ -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
} }

View File

@@ -69,6 +69,7 @@ namespace BAN
value_type* data() const value_type* data() const
{ {
ASSERT(m_data);
return m_data; return m_data;
} }
@@ -83,6 +84,7 @@ namespace BAN
Span slice(size_type start, size_type length = ~size_type(0)) const Span slice(size_type start, size_type length = ~size_type(0)) const
{ {
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;

View File

@@ -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;
@@ -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]);
} }
} }

View File

@@ -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:
@@ -247,12 +246,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(' ');
} }
} }

View File

@@ -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>;

View File

@@ -126,16 +126,14 @@ 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();
} }
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);
} }
template<typename T> template<typename T>
@@ -159,13 +157,12 @@ 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;
} }
other.clear(); other.clear();
@@ -174,13 +171,12 @@ 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;
} }
return *this; return *this;

View File

@@ -381,46 +381,19 @@ 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 (new_data == nullptr)
if constexpr (BAN::is_trivially_copyable_v<T>) return Error::from_errno(ENOMEM);
for (size_type i = 0; i < m_size; i++)
{ {
if constexpr (BAN::reallocator) new (new_data + i) T(move(m_data[i]));
{ m_data[i].~T();
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 BAN::deallocator(m_data);
{ m_data = new_data;
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
for (size_type i = 0; i < m_size; i++)
{
new (new_data + i) T(move(m_data[i]));
m_data[i].~T();
}
BAN::deallocator(m_data);
m_data = new_data;
}
m_capacity = new_cap; m_capacity = new_cap;
return {}; return {};
} }

Binary file not shown.

View File

@@ -25,7 +25,6 @@ set(KERNEL_SOURCES
kernel/Epoll.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
@@ -51,7 +50,6 @@ set(KERNEL_SOURCES
kernel/InterruptController.cpp kernel/InterruptController.cpp
kernel/kernel.cpp kernel/kernel.cpp
kernel/Lock/SpinLock.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
@@ -139,8 +137,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 +147,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,7 +162,10 @@ 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
# Ehhh don't do this but for now libc uses the same stuff kernel can use
# This won't work after libc starts using sse implemetations tho
../userspace/libraries/LibC/arch/${BANAN_ARCH}/string.S
) )
set(LIBDEFLATE_SOURCE set(LIBDEFLATE_SOURCE

View File

@@ -21,11 +21,6 @@ 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_post_heap_done = 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;
@@ -72,7 +67,7 @@ namespace Kernel
void PageTable::initialize_post_heap() void PageTable::initialize_post_heap()
{ {
s_is_post_heap_done = true; // NOTE: this is no-op as our 32 bit target does not use hhdm
} }
void PageTable::initial_load() void PageTable::initial_load()
@@ -146,9 +141,9 @@ namespace Kernel
} }
template<typename T> template<typename T>
static uint64_t* P2V(const T paddr) static vaddr_t P2V(const T paddr)
{ {
return reinterpret_cast<uint64_t*>(reinterpret_cast<paddr_t>(paddr) - g_boot_info.kernel_paddr + KERNEL_OFFSET); return (paddr_t)paddr - g_boot_info.kernel_paddr + KERNEL_OFFSET;
} }
void PageTable::initialize_kernel() void PageTable::initialize_kernel()
@@ -198,18 +193,13 @@ namespace Kernel
{ {
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF; constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF; constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
const uint64_t* pdpt = P2V(m_highest_paging_struct); uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
ASSERT(pdpt[pdpte] & Flags::Present); ASSERT(pdpt[pdpte] & 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);
ASSERT(!(pd[pde] & Flags::Present)); ASSERT(!(pd[pde] & Flags::Present));
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present; pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
ASSERT(pt[pte] == 0);
pt[pte] = Flags::Reserved;
} }
void PageTable::map_fast_page(paddr_t paddr) void PageTable::map_fast_page(paddr_t paddr)
@@ -224,14 +214,14 @@ namespace Kernel
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF; constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF; constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct); uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->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));
ASSERT(!(pt[pte] & Flags::Present)); ASSERT(!(pt[pte] & Flags::Present));
pt[pte] = paddr | Flags::ReadWrite | Flags::Present; pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory"); invalidate(fast_page(), false);
} }
void PageTable::unmap_fast_page() void PageTable::unmap_fast_page()
@@ -244,14 +234,14 @@ namespace Kernel
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF; constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF; constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct); uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->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));
ASSERT(pt[pte] & Flags::Present); ASSERT(pt[pte] & Flags::Present);
pt[pte] = Flags::Reserved; pt[pte] = 0;
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory"); invalidate(fast_page(), false);
} }
BAN::ErrorOr<PageTable*> PageTable::create_userspace() BAN::ErrorOr<PageTable*> PageTable::create_userspace()
@@ -273,7 +263,7 @@ namespace Kernel
m_highest_paging_struct = V2P(kmalloc(32, 32, true)); m_highest_paging_struct = V2P(kmalloc(32, 32, true));
ASSERT(m_highest_paging_struct); ASSERT(m_highest_paging_struct);
uint64_t* pdpt = P2V(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;
@@ -286,17 +276,18 @@ namespace Kernel
if (m_highest_paging_struct == 0) if (m_highest_paging_struct == 0)
return; return;
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 < 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);
} }
@@ -307,43 +298,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_post_heap_done)
{
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)
{ {
@@ -351,14 +314,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);
@@ -377,16 +339,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)
@@ -398,10 +356,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());
@@ -436,11 +401,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))
@@ -451,14 +416,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)
@@ -472,49 +433,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);
}
void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size) Processor::broadcast_smp_message({
{ .type = Processor::SMPMessage::Type::FlushTLB,
ASSERT(vaddr); .flush_tlb = {
ASSERT(vaddr % PAGE_SIZE == 0); .vaddr = vaddr,
.page_count = page_count
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
@@ -527,15 +453,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;
@@ -549,7 +475,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
@@ -591,8 +518,13 @@ namespace Kernel
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, true, false);
invalidate_range(vaddr, bytes / PAGE_SIZE, true); Processor::broadcast_smp_message({
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = bytes / PAGE_SIZE,
}
});
return true; return true;
} }
@@ -605,47 +537,48 @@ 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;
vaddr |= (vaddr_t)pte << 12; vaddr |= (vaddr_t)pte << 12;
ASSERT(reserve_page(vaddr)); ASSERT(reserve_page(vaddr));
return vaddr; return vaddr;
}
} }
pte = 0;
} }
pde = 0;
} }
// Find any free page // Find any free page
@@ -658,7 +591,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)
@@ -691,7 +624,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)
@@ -714,7 +647,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))
@@ -723,7 +656,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))
@@ -732,7 +665,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)

View File

@@ -1,13 +1,12 @@
.section .userspace, "ax" .section .userspace, "ax"
// stack contains // stack contains
// (4 bytes) return address (on return stack) // return address
// (4 bytes) return stack // return stack
// (4 bytes) return rflags // return rflags
// (8 bytes) restore sigmask // siginfo_t
// (36 bytes) siginfo_t // signal number
// (4 bytes) signal number // signal handler
// (4 bytes) signal handler
.global signal_trampoline .global signal_trampoline
signal_trampoline: signal_trampoline:
@@ -19,10 +18,6 @@ signal_trampoline:
pushl %eax pushl %eax
pushl %ebp pushl %ebp
movl 80(%esp), %eax
pushl %eax; addl $4, (%esp)
pushl (%eax)
// FIXME: populate these // FIXME: populate these
xorl %eax, %eax xorl %eax, %eax
pushl %eax // stack pushl %eax // stack
@@ -33,9 +28,9 @@ signal_trampoline:
pushl %eax // link pushl %eax // link
movl %esp, %edx // ucontext movl %esp, %edx // ucontext
leal 68(%esp), %esi // siginfo leal 60(%esp), %esi // siginfo
movl 64(%esp), %edi // signal number movl 56(%esp), %edi // signal number
movl 60(%esp), %eax // handlers movl 52(%esp), %eax // handlers
// align stack to 16 bytes // align stack to 16 bytes
movl %esp, %ebp movl %esp, %ebp
@@ -58,15 +53,7 @@ signal_trampoline:
movl %ebp, %esp movl %ebp, %esp
addl $24, %esp addl $24, %esp
// restore sigmask
movl $83, %eax // SYS_SIGPROCMASK
movl $3, %ebx // SIG_SETMASK
leal 72(%esp), %ecx // set
xorl %edx, %edx // oset
int $0xF0
// restore registers // restore registers
addl $8, %esp
popl %ebp popl %ebp
popl %eax popl %eax
popl %ebx popl %ebx
@@ -75,8 +62,8 @@ signal_trampoline:
popl %edi popl %edi
popl %esi popl %esi
// skip handler, number, siginfo_t, sigmask // skip handler, number, siginfo_t
addl $52, %esp addl $44, %esp
// restore flags // restore flags
popf popf

View File

@@ -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
@@ -31,6 +34,11 @@ start_kernel_thread:
.global start_userspace_thread .global start_userspace_thread
start_userspace_thread: start_userspace_thread:
call load_thread_sse
call get_thread_start_sp
movl %eax, %esp
movw $(0x20 | 3), %bx movw $(0x20 | 3), %bx
movw %bx, %ds movw %bx, %ds
movw %bx, %es movw %bx, %es

View File

@@ -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:

View File

@@ -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

View File

@@ -11,14 +11,13 @@
.code32 .code32
// video mode info, page align modules # multiboot2 header
.set multiboot_flags, (1 << 2) | (1 << 0)
.section .multiboot, "aw" .section .multiboot, "aw"
.align 8
multiboot_start: multiboot_start:
.long 0x1BADB002 .long 0x1BADB002
.long multiboot_flags .long (1 << 2) # page align modules
.long -(0x1BADB002 + multiboot_flags) .long -(0x1BADB002 + (1 << 2))
.long 0 .long 0
.long 0 .long 0
@@ -31,8 +30,7 @@ multiboot_start:
.long FB_HEIGHT .long FB_HEIGHT
.long FB_BPP .long FB_BPP
multiboot_end: multiboot_end:
.align 8
.section .multiboot2, "aw"
multiboot2_start: multiboot2_start:
.long 0xE85250D6 .long 0xE85250D6
.long 0 .long 0
@@ -68,6 +66,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)

View File

@@ -1,20 +1,21 @@
.macro intr_header, n .macro maybe_load_kernel_segments, n
pushal testb $3, \n(%esp)
testb $3, \n+8*4(%esp) jz 1f; jnp 1f
jz 1f
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 1:
.endm .endm
.macro intr_footer, n .macro maybe_load_userspace_segments, n
testb $3, \n+8*4(%esp) testb $3, \n(%esp)
jz 1f jz 1f; jnp 1f
call cpp_check_signal
movw $(0x20 | 3), %bx movw $(0x20 | 3), %bx
movw %bx, %ds movw %bx, %ds
movw %bx, %es movw %bx, %es
@@ -22,11 +23,14 @@
movw %bx, %fs movw %bx, %fs
movw $(0x38 | 3), %bx movw $(0x38 | 3), %bx
movw %bx, %gs movw %bx, %gs
1: popal 1:
.endm .endm
isr_stub: isr_stub:
intr_header 12 pushal
maybe_load_kernel_segments 44
cld
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
@@ -54,12 +58,15 @@ isr_stub:
movl %ebp, %esp movl %ebp, %esp
addl $24, %esp addl $24, %esp
intr_footer 12 maybe_load_userspace_segments 44
popal
addl $8, %esp addl $8, %esp
iret iret
irq_stub: irq_stub:
intr_header 12 pushal
maybe_load_kernel_segments 44
cld
movl 32(%esp), %edi # interrupt number movl 32(%esp), %edi # interrupt number
@@ -72,13 +79,38 @@ irq_stub:
movl %ebp, %esp movl %ebp, %esp
intr_footer 12 maybe_load_userspace_segments 44
popal
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
cld
leal 32(%esp), %edi # interrupt stack ptr
movl %esp, %esi # interrupt registers ptr
movl %esp, %ebp
andl $-16, %esp
subl $8, %esp
pushl %esi
pushl %edi
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 pushal
maybe_load_kernel_segments 36
cld
movl %esp, %ebp movl %esp, %ebp
andl $-16, %esp andl $-16, %esp
@@ -87,12 +119,15 @@ asm_ipi_handler:
movl %ebp, %esp movl %ebp, %esp
intr_footer 4 maybe_load_userspace_segments 36
popal
iret iret
.global asm_timer_handler .global asm_timer_handler
asm_timer_handler: asm_timer_handler:
intr_header 4 pushal
maybe_load_kernel_segments 36
cld
movl %esp, %ebp movl %esp, %ebp
andl $-16, %esp andl $-16, %esp
@@ -101,7 +136,8 @@ asm_timer_handler:
movl %ebp, %esp movl %ebp, %esp
intr_footer 4 maybe_load_userspace_segments 36
popal
iret iret
.macro isr n .macro isr n

View File

@@ -11,7 +11,6 @@ SECTIONS
{ {
g_kernel_execute_start = .; g_kernel_execute_start = .;
*(.multiboot) *(.multiboot)
*(.multiboot2)
*(.bananboot) *(.bananboot)
*(.text.*) *(.text.*)
} }

View File

@@ -23,7 +23,7 @@ namespace Kernel
SpinLock PageTable::s_fast_page_lock; SpinLock PageTable::s_fast_page_lock;
static constexpr vaddr_t s_hhdm_offset = 0xFFFF800000000000; static constexpr vaddr_t s_hhdm_offset = 0xFFFF800000000000;
static bool s_is_post_heap_done = false; static bool s_is_hddm_initialized = false;
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF; constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask; constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
@@ -376,7 +376,7 @@ namespace Kernel
V2P = &FuncsHHDM::V2P; V2P = &FuncsHHDM::V2P;
P2V = &FuncsHHDM::P2V; P2V = &FuncsHHDM::P2V;
s_is_post_heap_done = true; s_is_hddm_initialized = true;
// This is a hack to unmap fast page. fast page pt is copied // This is a hack to unmap fast page. fast page pt is copied
// while it is mapped, so we need to manually unmap it // while it is mapped, so we need to manually unmap it
@@ -485,7 +485,6 @@ namespace Kernel
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF; constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF; constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF; constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
constexpr uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
uint64_t* pml4 = P2V(m_highest_paging_struct); uint64_t* pml4 = P2V(m_highest_paging_struct);
ASSERT(!(pml4[pml4e] & Flags::Present)); ASSERT(!(pml4[pml4e] & Flags::Present));
@@ -498,10 +497,6 @@ namespace Kernel
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
ASSERT(!(pd[pde] & Flags::Present)); ASSERT(!(pd[pde] & Flags::Present));
pd[pde] = allocate_zeroed_page_aligned_page() | Flags::ReadWrite | Flags::Present; pd[pde] = allocate_zeroed_page_aligned_page() | Flags::ReadWrite | Flags::Present;
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
ASSERT(pt[pte] == 0);
pt[pte] = Flags::Reserved;
} }
void PageTable::map_fast_page(paddr_t paddr) void PageTable::map_fast_page(paddr_t paddr)
@@ -526,7 +521,7 @@ namespace Kernel
ASSERT(!(pt[pte] & Flags::Present)); ASSERT(!(pt[pte] & Flags::Present));
pt[pte] = paddr | Flags::ReadWrite | Flags::Present; pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory"); invalidate(fast_page(), false);
} }
void PageTable::unmap_fast_page() void PageTable::unmap_fast_page()
@@ -547,9 +542,9 @@ namespace Kernel
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask); uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
ASSERT(pt[pte] & Flags::Present); ASSERT(pt[pte] & Flags::Present);
pt[pte] = Flags::Reserved; pt[pte] = 0;
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory"); invalidate(fast_page(), false);
} }
BAN::ErrorOr<PageTable*> PageTable::create_userspace() BAN::ErrorOr<PageTable*> PageTable::create_userspace()
@@ -617,39 +612,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_post_heap_done)
{
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)
{ {
@@ -657,14 +623,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());
@@ -693,27 +658,30 @@ namespace Kernel
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask); uint64_t* pt = P2V(pd[pde] & s_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());
@@ -774,12 +742,9 @@ namespace Kernel
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;
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)
@@ -795,66 +760,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);
}
void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size) Processor::broadcast_smp_message({
{ .type = Processor::SMPMessage::Type::FlushTLB,
ASSERT(vaddr); .flush_tlb = {
ASSERT(vaddr % PAGE_SIZE == 0); .vaddr = vaddr,
.page_count = page_count
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
@@ -901,13 +814,13 @@ namespace Kernel
return page_data & s_page_addr_mask; return page_data & s_page_addr_mask;
} }
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool invalidate) bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
{ {
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, MemoryType::Normal, send_smp_message);
return true; return true;
} }
@@ -922,7 +835,13 @@ namespace Kernel
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, true, false);
invalidate_range(vaddr, bytes / PAGE_SIZE, true); Processor::broadcast_smp_message({
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = bytes / PAGE_SIZE,
}
});
return true; return true;
} }
@@ -936,9 +855,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;
@@ -955,8 +874,10 @@ 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); const uint64_t* pml4 = 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); const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
@@ -976,24 +897,22 @@ namespace Kernel
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask); const uint64_t* pt = P2V(pd[pde] & s_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 |= static_cast<uint64_t>(pml4e) << 39;
vaddr |= static_cast<uint64_t>(pdpte) << 30; vaddr |= static_cast<uint64_t>(pdpte) << 30;
vaddr |= static_cast<uint64_t>(pde) << 21; vaddr |= static_cast<uint64_t>(pde) << 21;
vaddr |= static_cast<uint64_t>(pte) << 12; vaddr |= static_cast<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) for (vaddr_t uc_vaddr = uc_vaddr_start; uc_vaddr < uc_vaddr_end; uc_vaddr += PAGE_SIZE)
@@ -1005,7 +924,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)
@@ -1018,7 +937,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);
@@ -1047,7 +966,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

View File

@@ -1,13 +1,12 @@
.section .userspace, "ax" .section .userspace, "ax"
// stack contains // stack contains
// (8 bytes) return address (on return stack) // return address
// (8 bytes) return stack // return stack
// (8 bytes) return rflags // return rflags
// (8 bytes) restore sigmask // siginfo_t
// (56 bytes) siginfo_t // signal number
// (8 bytes) signal number // signal handler
// (8 bytes) signal handler
.global signal_trampoline .global signal_trampoline
signal_trampoline: signal_trampoline:
@@ -27,10 +26,6 @@ signal_trampoline:
pushq %rax pushq %rax
pushq %rbp pushq %rbp
movq 208(%rsp), %rax
pushq %rax; addq $(128 + 8), (%rsp)
pushq (%rax)
// FIXME: populate these // FIXME: populate these
xorq %rax, %rax xorq %rax, %rax
pushq %rax // stack pushq %rax // stack
@@ -40,9 +35,9 @@ signal_trampoline:
pushq %rax // link pushq %rax // link
movq %rsp, %rdx // ucontext movq %rsp, %rdx // ucontext
leaq 192(%rsp), %rsi // siginfo leaq 176(%rsp), %rsi // siginfo
movq 184(%rsp), %rdi // signal number movq 168(%rsp), %rdi // signal number
movq 176(%rsp), %rax // handler movq 160(%rsp), %rax // handler
// align stack to 16 bytes // align stack to 16 bytes
movq %rsp, %rbp movq %rsp, %rbp
@@ -60,15 +55,7 @@ signal_trampoline:
movq %rbp, %rsp movq %rbp, %rsp
addq $40, %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 // restore registers
addq $16, %rsp
popq %rbp popq %rbp
popq %rax popq %rax
popq %rbx popq %rbx
@@ -85,13 +72,13 @@ signal_trampoline:
popq %r14 popq %r14
popq %r15 popq %r15
// skip handler, number, siginfo_t, sigmask // skip handler, number, siginfo_t
addq $80, %rsp addq $72, %rsp
// restore flags // restore flags
popfq popfq
movq (%rsp), %rsp movq (%rsp), %rsp
// return over red-zone // return over red-zone and siginfo_t
ret $128 ret $128

View File

@@ -33,7 +33,7 @@ sys_fork_trampoline:
call read_ip call read_ip
testq %rax, %rax testq %rax, %rax
jz .done je .done
movq %rax, %rsi movq %rax, %rsi
movq %rsp, %rdi movq %rsp, %rdi

View File

@@ -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,11 @@ start_kernel_thread:
.global start_userspace_thread .global start_userspace_thread
start_userspace_thread: start_userspace_thread:
call load_thread_sse
call get_thread_start_sp
movq %rax, %rsp
swapgs swapgs
iretq iretq

View File

@@ -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:

View File

@@ -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

View File

@@ -11,28 +11,26 @@
.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"
.align 8
multiboot_start: multiboot_start:
.long 0x1BADB002 .long 0x1BADB002
.long multiboot_flags .long (1 << 2) # page align modules
.long -(0x1BADB002 + multiboot_flags) .long -(0x1BADB002 + (1 << 2))
.long V2P(multiboot_start) .long 0
.long V2P(g_kernel_start) .long 0
.long V2P(g_kernel_bss_start) .long 0
.long V2P(g_kernel_end) .long 0
.long V2P(_start) .long 0
.long 0 .long 0
.long FB_WIDTH .long FB_WIDTH
.long FB_HEIGHT .long FB_HEIGHT
.long FB_BPP .long FB_BPP
multiboot_end: multiboot_end:
.align 8
.section .multiboot2, "aw"
multiboot2_start: multiboot2_start:
.long 0xE85250D6 .long 0xE85250D6
.long 0 .long 0
@@ -68,6 +66,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)

View File

@@ -1,4 +1,12 @@
.macro intr_header, n .macro swapgs_if_necessary, n
testb $3, \n(%rsp)
jz 1f; jnp 1f
swapgs
1:
.endm
.macro pushaq, n
swapgs_if_necessary \n
pushq %rax pushq %rax
pushq %rcx pushq %rcx
pushq %rdx pushq %rdx
@@ -14,18 +22,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, n
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
@@ -40,10 +40,12 @@
popq %rdx popq %rdx
popq %rcx popq %rcx
popq %rax popq %rax
swapgs_if_necessary \n
.endm .endm
isr_stub: isr_stub:
intr_header 24 pushaq 24
cld
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 +58,43 @@ isr_stub:
call cpp_isr_handler call cpp_isr_handler
addq $32, %rsp addq $32, %rsp
intr_footer 24 popaq 24
addq $16, %rsp addq $16, %rsp
iretq iretq
irq_stub: irq_stub:
intr_header 24 pushaq 24
xorq %rbp, %rbp cld
movq 120(%rsp), %rdi # irq number movq 120(%rsp), %rdi # irq number
call cpp_irq_handler call cpp_irq_handler
intr_footer 24 popaq 24
addq $16, %rsp addq $16, %rsp
iretq iretq
.global asm_yield_handler
asm_yield_handler:
pushaq 8
cld
leaq 120(%rsp), %rdi # interrupt stack ptr
movq %rsp, %rsi # interrupt register ptr
call cpp_yield_handler
popaq 8
iretq
.global asm_ipi_handler .global asm_ipi_handler
asm_ipi_handler: asm_ipi_handler:
intr_header 8 pushaq 8
xorq %rbp, %rbp cld
call cpp_ipi_handler call cpp_ipi_handler
intr_footer 8 popaq 8
iretq iretq
.global asm_timer_handler .global asm_timer_handler
asm_timer_handler: asm_timer_handler:
intr_header 8 pushaq 8
xorq %rbp, %rbp cld
call cpp_timer_handler call cpp_timer_handler
intr_footer 8 popaq 8
iretq iretq
.macro isr n .macro isr n

View File

@@ -11,7 +11,6 @@ SECTIONS
{ {
g_kernel_execute_start = .; g_kernel_execute_start = .;
*(.multiboot) *(.multiboot)
*(.multiboot2)
*(.bananboot) *(.bananboot)
*(.text.*) *(.text.*)
} }
@@ -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 = .;

View File

@@ -1,34 +1,44 @@
#pragma once #pragma once
#include <BAN/MacroUtils.h> #include <kernel/Attributes.h>
#include <kernel/IDT.h>
#include <stdint.h>
#include <sys/syscall.h>
#if defined(__x86_64__) namespace Kernel
#define _kas_instruction "syscall" {
#define _kas_result rax
#define _kas_arguments rdi, rsi, rdx, r10, r8, r9 ALWAYS_INLINE long syscall(int syscall, uintptr_t arg1 = 0, uintptr_t arg2 = 0, uintptr_t arg3 = 0, uintptr_t arg4 = 0, uintptr_t arg5 = 0)
#define _kas_globbers rcx, rdx, rdi, rsi, r8, r9, r10, r11 {
#elif defined(__i686__) long ret;
#define _kas_instruction "int $0xF0" #if ARCH(x86_64)
#define _kas_result eax register uintptr_t r10 asm("r10") = arg3;
#define _kas_arguments eax, ebx, ecx, edx, esi, edi register uintptr_t r8 asm( "r8") = arg4;
#define _kas_globbers register uintptr_t r9 asm( "r9") = arg5;
asm volatile(
"syscall"
: "=a"(ret)
, "+D"(syscall)
, "+S"(arg1)
, "+d"(arg2)
, "+r"(r10)
, "+r"(r8)
, "+r"(r9)
:: "rcx", "r11", "memory");
#elif ARCH(i686)
asm volatile(
"int %[irq]"
: "=a"(ret)
: [irq]"i"(static_cast<int>(IRQ_SYSCALL)) // WTF GCC 15
, "a"(syscall)
, "b"(arg1)
, "c"(arg2)
, "d"(arg3)
, "S"(arg4)
, "D"(arg5)
: "memory");
#endif #endif
return ret;
}
#define _kas_argument_var(index, value) register long _kas_a##index asm(_ban_stringify(_ban_get(index, _kas_arguments))) = (long)value; }
#define _kas_dummy_var(index, value) register long _kas_d##index asm(#value);
#define _kas_input(index, _) "r"(_kas_a##index)
#define _kas_output(index, _) , "=r"(_kas_d##index)
#define _kas_globber(_, value) #value
#define _kas_syscall(...) ({ \
register long _kas_ret asm(_ban_stringify(_kas_result)); \
_ban_for_each(_kas_argument_var, __VA_ARGS__) \
_ban_for_each(_kas_dummy_var, _kas_globbers) \
asm volatile( \
_kas_instruction \
: "=r"(_kas_ret) _ban_for_each(_kas_output, _kas_globbers) \
: _ban_for_each_comma(_kas_input, __VA_ARGS__) \
: "cc", "memory"); \
(void)_kas_a0; /* require 1 argument */ \
_kas_ret; \
})

View File

@@ -6,7 +6,7 @@
namespace Kernel namespace Kernel
{ {
class AC97AudioController final : public AudioController, public Interruptable class AC97AudioController : public AudioController, public Interruptable
{ {
public: public:
static BAN::ErrorOr<void> create(PCI::Device& pci_device); static BAN::ErrorOr<void> create(PCI::Device& pci_device);
@@ -23,15 +23,11 @@ namespace Kernel
uint32_t get_current_pin() const override { return 0; } uint32_t get_current_pin() const override { return 0; }
BAN::ErrorOr<void> set_current_pin(uint32_t pin) override { if (pin != 0) return BAN::Error::from_errno(EINVAL); return {}; } BAN::ErrorOr<void> set_current_pin(uint32_t pin) override { if (pin != 0) return BAN::Error::from_errno(EINVAL); return {}; }
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
private: private:
AC97AudioController(PCI::Device& pci_device) AC97AudioController(PCI::Device& pci_device)
: m_pci_device(pci_device) : m_pci_device(pci_device)
{ } { }
uint32_t get_volume_data() const;
BAN::ErrorOr<void> initialize(); BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> initialize_bld(); BAN::ErrorOr<void> initialize_bld();
BAN::ErrorOr<void> initialize_interrupts(); BAN::ErrorOr<void> initialize_interrupts();

View File

@@ -1,11 +1,8 @@
#pragma once #pragma once
#include <kernel/Device/Device.h> #include <kernel/Device/Device.h>
#include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/PCI.h> #include <kernel/PCI.h>
#include <sys/ioctl.h>
namespace Kernel namespace Kernel
{ {
@@ -19,7 +16,6 @@ namespace Kernel
protected: protected:
AudioController(); AudioController();
BAN::ErrorOr<void> initialize();
virtual void handle_new_data() = 0; virtual void handle_new_data() = 0;
@@ -30,10 +26,8 @@ namespace Kernel
virtual uint32_t get_current_pin() const = 0; virtual uint32_t get_current_pin() const = 0;
virtual BAN::ErrorOr<void> set_current_pin(uint32_t) = 0; virtual BAN::ErrorOr<void> set_current_pin(uint32_t) = 0;
virtual BAN::ErrorOr<void> set_volume_mdB(int32_t) = 0;
bool can_read_impl() const override { return false; } bool can_read_impl() const override { return false; }
bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return !m_sample_data->full(); } bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return m_sample_data_size < m_sample_data_capacity; }
bool has_error_impl() const override { return false; } bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override { return false; } bool has_hungup_impl() const override { return false; }
@@ -46,9 +40,9 @@ namespace Kernel
mutable SpinLock m_spinlock; mutable SpinLock m_spinlock;
static constexpr size_t m_sample_data_capacity = 1 << 20; static constexpr size_t m_sample_data_capacity = 1 << 20;
BAN::UniqPtr<ByteRingBuffer> m_sample_data; uint8_t m_sample_data[m_sample_data_capacity];
size_t m_sample_data_head { 0 };
snd_volume_info m_volume_info {}; size_t m_sample_data_size { 0 };
private: private:
const dev_t m_rdev; const dev_t m_rdev;

View File

@@ -8,7 +8,7 @@ namespace Kernel
class HDAudioController; class HDAudioController;
class HDAudioFunctionGroup final : public AudioController class HDAudioFunctionGroup : public AudioController
{ {
public: public:
static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&); static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&);
@@ -24,8 +24,6 @@ namespace Kernel
uint32_t get_current_pin() const override; uint32_t get_current_pin() const override;
BAN::ErrorOr<void> set_current_pin(uint32_t) override; BAN::ErrorOr<void> set_current_pin(uint32_t) override;
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
void handle_new_data() override; void handle_new_data() override;
private: private:
@@ -48,12 +46,15 @@ namespace Kernel
BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path); BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path);
uint16_t get_format_data() const; uint16_t get_format_data() const;
uint16_t get_volume_data() const;
size_t bdl_offset() const; size_t bdl_offset() const;
void queue_bdl_data(); void queue_bdl_data();
private: private:
static constexpr size_t m_max_path_length = 16;
// use 6 512 sample BDL entries // use 6 512 sample BDL entries
// each entry is ~10.7 ms at 48 kHz // each entry is ~10.7 ms at 48 kHz
// -> total buffered audio is 64 ms // -> total buffered audio is 64 ms
@@ -65,7 +66,6 @@ namespace Kernel
const uint8_t m_cid; const uint8_t m_cid;
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths; BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
BAN::Vector<const HDAudio::AFGWidget*> m_output_pins;
size_t m_output_path_index { SIZE_MAX }; size_t m_output_path_index { SIZE_MAX };
uint8_t m_stream_id { 0xFF }; uint8_t m_stream_id { 0xFF };

View File

@@ -50,21 +50,9 @@ namespace Kernel::HDAudio
{ {
bool input; bool input;
bool output; bool output;
bool display; // HDMI or DP
uint32_t config;
} pin_complex; } pin_complex;
}; };
struct Amplifier
{
uint8_t offset;
uint8_t num_steps;
uint8_t step_size;
bool mute;
};
BAN::Optional<Amplifier> output_amplifier;
BAN::Vector<uint16_t> connections; BAN::Vector<uint16_t> connections;
}; };

View File

@@ -11,7 +11,6 @@ namespace Kernel::HDAudio
VMIN = 0x02, VMIN = 0x02,
VMAJ = 0x03, VMAJ = 0x03,
GCTL = 0x08, GCTL = 0x08,
STATESTS = 0x0E,
INTCTL = 0x20, INTCTL = 0x20,
INTSTS = 0x24, INTSTS = 0x24,

View File

@@ -44,7 +44,7 @@ namespace Kernel
struct BootModule struct BootModule
{ {
paddr_t start; paddr_t start;
uint64_t size; size_t size;
}; };
struct BootInfo struct BootInfo

View File

@@ -76,7 +76,6 @@
namespace Debug namespace Debug
{ {
void dump_stack_trace(); void dump_stack_trace();
void dump_stack_trace(uintptr_t ip, uintptr_t bp);
void dump_qr_code(); void dump_qr_code();
void putchar(char); void putchar(char);

View File

@@ -37,8 +37,6 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override; virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override; virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
BAN::ErrorOr<long> ioctl_impl(int cmd, void* arg) override;
virtual bool can_read_impl() const override { return true; } virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return true; } virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; } virtual bool has_error_impl() const override { return false; }

View File

@@ -1,52 +0,0 @@
#pragma once
#include <kernel/FS/Inode.h>
namespace Kernel
{
class EventFD final : public Inode
{
public:
static BAN::ErrorOr<BAN::RefPtr<Inode>> create(uint64_t initval, bool semaphore);
ino_t ino() const override { return 0; }
Mode mode() const override { return { Mode::IFCHR | Mode::IRUSR | Mode::IWUSR }; }
nlink_t nlink() const override { return ref_count(); }
uid_t uid() const override { return 0; }
gid_t gid() const override { return 0; }
off_t size() const override { return 0; }
timespec atime() const override { return {}; }
timespec mtime() const override { return {}; }
timespec ctime() const override { return {}; }
blksize_t blksize() const override { return 8; }
blkcnt_t blocks() const override { return 0; }
dev_t dev() const override { return 0; }
dev_t rdev() const override { return 0; }
const FileSystem* filesystem() const override { return nullptr; }
protected:
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
BAN::ErrorOr<void> fsync_impl() final override { return {}; }
bool can_read_impl() const override { return m_value > 0; }
bool can_write_impl() const override { return m_value < UINT64_MAX - 1; }
bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override { return false; }
private:
EventFD(uint64_t initval, bool is_semaphore)
: m_is_semaphore(is_semaphore)
, m_value(initval)
{ }
private:
const bool m_is_semaphore;
uint64_t m_value;
ThreadBlocker m_thread_blocker;
};
}

View File

@@ -28,28 +28,36 @@ namespace Kernel
BAN_NON_COPYABLE(BlockBufferWrapper); BAN_NON_COPYABLE(BlockBufferWrapper);
public: public:
BlockBufferWrapper(BAN::Span<uint8_t> buffer, void (*callback)(void*, const uint8_t*), void* argument) BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool* used, Mutex* mutex, ThreadBlocker* blocker)
: m_buffer(buffer) : m_buffer(buffer)
, m_callback(callback) , m_used(used)
, m_argument(argument) , m_mutex(mutex)
{ } , m_blocker(blocker)
{
ASSERT(m_used && *m_used);
}
BlockBufferWrapper(BlockBufferWrapper&& other) { *this = BAN::move(other); } BlockBufferWrapper(BlockBufferWrapper&& other) { *this = BAN::move(other); }
~BlockBufferWrapper() ~BlockBufferWrapper()
{ {
if (m_callback == nullptr) if (m_used == nullptr)
return; return;
m_callback(m_argument, m_buffer.data()); m_mutex->lock();
*m_used = false;
m_blocker->unblock();
m_mutex->unlock();
} }
BlockBufferWrapper& operator=(BlockBufferWrapper&& other) BlockBufferWrapper& operator=(BlockBufferWrapper&& other)
{ {
this->m_buffer = other.m_buffer; this->m_buffer = other.m_buffer;
this->m_callback = other.m_callback; this->m_used = other.m_used;
this->m_argument = other.m_argument; this->m_mutex = other.m_mutex;
this->m_blocker = other.m_blocker;
other.m_buffer = {}; other.m_buffer = {};
other.m_callback = nullptr; other.m_used = nullptr;
other.m_argument = nullptr; other.m_mutex = nullptr;
other.m_blocker = nullptr;
return *this; return *this;
} }
@@ -67,8 +75,9 @@ namespace Kernel
private: private:
BAN::Span<uint8_t> m_buffer; BAN::Span<uint8_t> m_buffer;
void (*m_callback)(void*, const uint8_t*); bool* m_used;
void* m_argument; Mutex* m_mutex;
ThreadBlocker* m_blocker;
}; };
public: public:
@@ -121,9 +130,6 @@ namespace Kernel
BAN::ErrorOr<void> initialize(size_t block_size); BAN::ErrorOr<void> initialize(size_t block_size);
private:
void destroy_callback(const uint8_t* buffer_ptr);
private: private:
struct BlockBuffer struct BlockBuffer
{ {
@@ -131,20 +137,10 @@ namespace Kernel
bool used { false }; bool used { false };
}; };
struct ThreadInfo
{
pid_t tid { 0 };
size_t buffers { 0 };
};
private: private:
static constexpr size_t max_threads = 8;
static constexpr size_t max_buffers_per_thread = 6;
Mutex m_buffer_mutex; Mutex m_buffer_mutex;
ThreadBlocker m_buffer_blocker; ThreadBlocker m_buffer_blocker;
BAN::Array<BlockBuffer, max_threads * max_buffers_per_thread> m_buffers; BAN::Array<BlockBuffer, 16> m_buffers;
BAN::Array<ThreadInfo, max_threads> m_thread_infos;
}; };
private: private:

View File

@@ -70,7 +70,6 @@ namespace Kernel
BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth); BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth);
BAN::ErrorOr<void> cleanup_default_links(); BAN::ErrorOr<void> cleanup_default_links();
BAN::ErrorOr<void> cleanup_data_blocks();
BAN::ErrorOr<void> cleanup_from_fs(); BAN::ErrorOr<void> cleanup_from_fs();
BAN::ErrorOr<void> sync(); BAN::ErrorOr<void> sync();

View File

@@ -113,8 +113,6 @@ namespace Kernel
BAN::ErrorOr<size_t> recvmsg(msghdr& message, int flags); BAN::ErrorOr<size_t> recvmsg(msghdr& message, int flags);
BAN::ErrorOr<void> getsockname(sockaddr* address, socklen_t* address_len); BAN::ErrorOr<void> getsockname(sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<void> getpeername(sockaddr* address, socklen_t* address_len); BAN::ErrorOr<void> getpeername(sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<void> getsockopt(int level, int option, void* value, socklen_t* value_len);
BAN::ErrorOr<void> setsockopt(int level, int option, const void* value, socklen_t value_len);
// General API // General API
BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer); BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer);
@@ -163,8 +161,6 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr&, int) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr&, int) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
// General API // General API
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); }

View File

@@ -2,7 +2,6 @@
#include <BAN/Array.h> #include <BAN/Array.h>
#include <kernel/FS/Inode.h> #include <kernel/FS/Inode.h>
#include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/ThreadBlocker.h> #include <kernel/ThreadBlocker.h>
namespace Kernel namespace Kernel
@@ -39,7 +38,7 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override; virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
virtual BAN::ErrorOr<void> fsync_impl() final override { return {}; } virtual BAN::ErrorOr<void> fsync_impl() final override { return {}; }
virtual bool can_read_impl() const override { return !m_buffer->empty(); } virtual bool can_read_impl() const override { return m_buffer_size > 0; }
virtual bool can_write_impl() const override { return true; } virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return m_reading_count == 0; } virtual bool has_error_impl() const override { return m_reading_count == 0; }
virtual bool has_hungup_impl() const override { return m_writing_count == 0; } virtual bool has_hungup_impl() const override { return m_writing_count == 0; }
@@ -55,7 +54,9 @@ namespace Kernel
timespec m_ctime {}; timespec m_ctime {};
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
BAN::UniqPtr<ByteRingBuffer> m_buffer; BAN::Array<uint8_t, PAGE_SIZE> m_buffer;
BAN::Atomic<size_t> m_buffer_size { 0 };
size_t m_buffer_tail { 0 };
BAN::Atomic<uint32_t> m_writing_count { 1 }; BAN::Atomic<uint32_t> m_writing_count { 1 };
BAN::Atomic<uint32_t> m_reading_count { 1 }; BAN::Atomic<uint32_t> m_reading_count { 1 };

View File

@@ -1,11 +1,12 @@
#pragma once #pragma once
#include <kernel/BootInfo.h> #include <kernel/BootInfo.h>
#include <kernel/FS/Inode.h> #include <kernel/FS/FileSystem.h>
namespace Kernel namespace Kernel
{ {
BAN::ErrorOr<bool> unpack_boot_module_into_directory(BAN::RefPtr<Inode>, const BootModule&); bool is_ustar_boot_module(const BootModule&);
BAN::ErrorOr<void> unpack_boot_module_into_filesystem(BAN::RefPtr<FileSystem>, const BootModule&);
} }

View File

@@ -20,10 +20,11 @@ namespace Kernel
constexpr uint8_t IRQ_MSI_BASE = 0x80; constexpr uint8_t IRQ_MSI_BASE = 0x80;
constexpr uint8_t IRQ_MSI_END = 0xF0; constexpr uint8_t IRQ_MSI_END = 0xF0;
#if ARCH(i686) #if ARCH(i686)
constexpr uint8_t IRQ_SYSCALL = 0xF0; // hard coded in kernel/API/Syscall.h constexpr uint8_t IRQ_SYSCALL = 0xF0;
#endif #endif
constexpr uint8_t IRQ_IPI = 0xF1; constexpr uint8_t IRQ_YIELD = 0xF1;
constexpr uint8_t IRQ_TIMER = 0xF2; constexpr uint8_t IRQ_IPI = 0xF2;
constexpr uint8_t IRQ_TIMER = 0xF3;
#if ARCH(x86_64) #if ARCH(x86_64)
struct GateDescriptor struct GateDescriptor

View File

@@ -27,6 +27,7 @@ namespace Kernel
uintptr_t r10; uintptr_t r10;
uintptr_t r9; uintptr_t r9;
uintptr_t r8; uintptr_t r8;
uintptr_t rdi; uintptr_t rdi;
uintptr_t rsi; uintptr_t rsi;
uintptr_t rbp; uintptr_t rbp;
@@ -35,18 +36,6 @@ namespace Kernel
uintptr_t rcx; uintptr_t rcx;
uintptr_t rax; uintptr_t rax;
}; };
struct YieldRegisters
{
uintptr_t r15;
uintptr_t r14;
uintptr_t r13;
uintptr_t r12;
uintptr_t rbp;
uintptr_t rbx;
uintptr_t ret;
uintptr_t sp;
uintptr_t ip;
};
#elif ARCH(i686) #elif ARCH(i686)
struct InterruptRegisters struct InterruptRegisters
{ {
@@ -59,16 +48,6 @@ namespace Kernel
uintptr_t ecx; uintptr_t ecx;
uintptr_t eax; uintptr_t eax;
}; };
struct YieldRegisters
{
uintptr_t ebp;
uintptr_t edi;
uintptr_t esi;
uintptr_t ebx;
uintptr_t ret;
uintptr_t sp;
uintptr_t ip;
};
#endif #endif
} }

View File

@@ -1,76 +0,0 @@
#pragma once
#include <BAN/ByteSpan.h>
#include <BAN/UniqPtr.h>
#include <BAN/Vector.h>
#include <kernel/Memory/Types.h>
namespace Kernel
{
class ByteRingBuffer
{
public:
static BAN::ErrorOr<BAN::UniqPtr<ByteRingBuffer>> create(size_t size);
~ByteRingBuffer();
void push(BAN::ConstByteSpan data)
{
ASSERT(data.size() + m_size <= m_capacity);
uint8_t* buffer_head = reinterpret_cast<uint8_t*>(m_vaddr) + (m_tail + m_size) % m_capacity;
memcpy(buffer_head, data.data(), data.size());
m_size += data.size();
}
void pop(size_t size)
{
ASSERT(size <= m_size);
m_tail = (m_tail + size) % m_capacity;
m_size -= size;
}
void pop_back(size_t size)
{
ASSERT(size <= m_size);
m_size -= size;
}
BAN::ConstByteSpan get_data() const
{
const uint8_t* base = reinterpret_cast<const uint8_t*>(m_vaddr);
return { base + m_tail, m_size };
}
uint8_t front() const
{
ASSERT(!empty());
return reinterpret_cast<const uint8_t*>(m_vaddr)[m_tail];
}
uint8_t back() const
{
ASSERT(!empty());
return reinterpret_cast<const uint8_t*>(m_vaddr)[m_tail + m_size];
}
bool empty() const { return m_size == 0; }
bool full() const { return m_size == m_capacity; }
size_t free() const { return m_capacity - m_size; }
size_t size() const { return m_size; }
size_t capacity() const { return m_capacity; }
private:
ByteRingBuffer(size_t capacity)
: m_capacity(capacity)
{ }
private:
size_t m_size { 0 };
size_t m_tail { 0 };
const size_t m_capacity;
vaddr_t m_vaddr { 0 };
};
}

View File

@@ -18,8 +18,6 @@ namespace Kernel
static void initialize(); static void initialize();
static Heap& get(); static Heap& get();
void release_boot_modules();
paddr_t take_free_page(); paddr_t take_free_page();
void release_page(paddr_t); void release_page(paddr_t);

View File

@@ -28,20 +28,6 @@ namespace Kernel
private: private:
MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t, int status_flags); MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t, int status_flags);
private:
struct PhysicalPage
{
PhysicalPage(paddr_t paddr)
: paddr(paddr)
{ }
~PhysicalPage();
BAN::Atomic<uint32_t> ref_count { 1 };
const paddr_t paddr;
};
BAN::Vector<PhysicalPage*> m_physical_pages;
Mutex m_mutex;
}; };
} }

View File

@@ -100,21 +100,19 @@ namespace Kernel
static BAN::ErrorOr<PageTable*> create_userspace(); static BAN::ErrorOr<PageTable*> create_userspace();
~PageTable(); ~PageTable();
void unmap_page(vaddr_t, bool invalidate = true); void unmap_page(vaddr_t, bool send_smp_message = true);
void unmap_range(vaddr_t, size_t bytes); void unmap_range(vaddr_t, size_t bytes);
void map_page_at(paddr_t, vaddr_t, flags_t, MemoryType = MemoryType::Normal, bool invalidate = true); void map_page_at(paddr_t, vaddr_t, flags_t, MemoryType = MemoryType::Normal, bool send_smp_message = true);
void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t, MemoryType = MemoryType::Normal); void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t, MemoryType = MemoryType::Normal);
void remove_writable_from_range(vaddr_t, size_t);
paddr_t physical_address_of(vaddr_t) const; paddr_t physical_address_of(vaddr_t) const;
flags_t get_page_flags(vaddr_t) const; flags_t get_page_flags(vaddr_t) const;
bool is_page_free(vaddr_t) const; bool is_page_free(vaddr_t) const;
bool is_range_free(vaddr_t, size_t bytes) const; bool is_range_free(vaddr_t, size_t bytes) const;
bool reserve_page(vaddr_t, bool only_free = true, bool invalidate = true); bool reserve_page(vaddr_t, bool only_free = true, bool send_smp_message = true);
bool reserve_range(vaddr_t, size_t bytes, bool only_free = true); bool reserve_range(vaddr_t, size_t bytes, bool only_free = true);
vaddr_t reserve_free_page(vaddr_t first_address, vaddr_t last_address = UINTPTR_MAX); vaddr_t reserve_free_page(vaddr_t first_address, vaddr_t last_address = UINTPTR_MAX);
@@ -123,9 +121,6 @@ namespace Kernel
void load(); void load();
void initial_load(); void initial_load();
void invalidate_page(vaddr_t addr, bool send_smp_message) { invalidate_range(addr, 1, send_smp_message); }
void invalidate_range(vaddr_t addr, size_t pages, bool send_smp_message);
InterruptState lock() const { return m_lock.lock(); } InterruptState lock() const { return m_lock.lock(); }
void unlock(InterruptState state) const { m_lock.unlock(state); } void unlock(InterruptState state) const { m_lock.unlock(state); }
@@ -138,6 +133,8 @@ namespace Kernel
void map_kernel_memory(); void map_kernel_memory();
void prepare_fast_page(); void prepare_fast_page();
static void invalidate(vaddr_t, bool send_smp_message);
static void map_fast_page(paddr_t); static void map_fast_page(paddr_t);
static void unmap_fast_page(); static void unmap_fast_page();

View File

@@ -10,7 +10,7 @@ namespace Kernel
class PhysicalRange class PhysicalRange
{ {
public: public:
PhysicalRange(paddr_t, uint64_t); PhysicalRange(paddr_t, size_t);
paddr_t reserve_page(); paddr_t reserve_page();
void release_page(paddr_t); void release_page(paddr_t);

View File

@@ -4,7 +4,7 @@
#if ARCH(x86_64) #if ARCH(x86_64)
#define KERNEL_OFFSET 0xFFFFFFFF80000000 #define KERNEL_OFFSET 0xFFFFFFFF80000000
#define USERSPACE_END 0x800000000000 #define USERSPACE_END 0xFFFF800000000000
#elif ARCH(i686) #elif ARCH(i686)
#define KERNEL_OFFSET 0xC0000000 #define KERNEL_OFFSET 0xC0000000
#define USERSPACE_END 0xC0000000 #define USERSPACE_END 0xC0000000

View File

@@ -20,6 +20,8 @@ namespace Kernel
static BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> create_to_vaddr_range(PageTable&, vaddr_t vaddr_start, vaddr_t vaddr_end, size_t, PageTable::flags_t flags, bool preallocate_pages, bool add_guard_pages); static BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> create_to_vaddr_range(PageTable&, vaddr_t vaddr_start, vaddr_t vaddr_end, size_t, PageTable::flags_t flags, bool preallocate_pages, bool add_guard_pages);
~VirtualRange(); ~VirtualRange();
BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> clone(PageTable&);
vaddr_t vaddr() const { return m_vaddr + (m_has_guard_pages ? PAGE_SIZE : 0); } vaddr_t vaddr() const { return m_vaddr + (m_has_guard_pages ? PAGE_SIZE : 0); }
size_t size() const { return m_size - (m_has_guard_pages ? 2 * PAGE_SIZE : 0); } size_t size() const { return m_size - (m_has_guard_pages ? 2 * PAGE_SIZE : 0); }
PageTable::flags_t flags() const { return m_flags; } PageTable::flags_t flags() const { return m_flags; }

View File

@@ -31,18 +31,35 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::UniqPtr<ARPTable>> create(); static BAN::ErrorOr<BAN::UniqPtr<ARPTable>> create();
~ARPTable();
BAN::ErrorOr<BAN::MACAddress> get_mac_from_ipv4(NetworkInterface&, BAN::IPv4Address); BAN::ErrorOr<BAN::MACAddress> get_mac_from_ipv4(NetworkInterface&, BAN::IPv4Address);
BAN::ErrorOr<void> handle_arp_packet(NetworkInterface&, BAN::ConstByteSpan); void add_arp_packet(NetworkInterface&, BAN::ConstByteSpan);
private: private:
ARPTable() = default; ARPTable();
void packet_handle_task();
BAN::ErrorOr<void> handle_arp_packet(NetworkInterface&, const ARPPacket&);
private: private:
SpinLock m_arp_table_lock; struct PendingArpPacket
{
NetworkInterface& interface;
ARPPacket packet;
};
private:
SpinLock m_table_lock;
SpinLock m_pending_lock;
BAN::HashMap<BAN::IPv4Address, BAN::MACAddress> m_arp_table; BAN::HashMap<BAN::IPv4Address, BAN::MACAddress> m_arp_table;
Thread* m_thread { nullptr };
BAN::CircularQueue<PendingArpPacket, 128> m_pending_packets;
ThreadBlocker m_pending_thread_blocker;
friend class BAN::UniqPtr<ARPTable>; friend class BAN::UniqPtr<ARPTable>;
}; };

View File

@@ -23,14 +23,14 @@ namespace Kernel
static BAN::ErrorOr<BAN::RefPtr<E1000>> create(PCI::Device&); static BAN::ErrorOr<BAN::RefPtr<E1000>> create(PCI::Device&);
~E1000(); ~E1000();
BAN::MACAddress get_mac_address() const override { return m_mac_address; } virtual BAN::MACAddress get_mac_address() const override { return m_mac_address; }
bool link_up() override { return m_link_up; } virtual bool link_up() override { return m_link_up; }
int link_speed() override; virtual int link_speed() override;
size_t payload_mtu() const override { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); } virtual size_t payload_mtu() const override { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); }
void handle_irq() final override; virtual void handle_irq() final override;
protected: protected:
E1000(PCI::Device& pci_device) E1000(PCI::Device& pci_device)
@@ -45,12 +45,12 @@ namespace Kernel
uint32_t read32(uint16_t reg); uint32_t read32(uint16_t reg);
void write32(uint16_t reg, uint32_t value); void write32(uint16_t reg, uint32_t value);
BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) override; virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override;
bool can_read_impl() const override { return false; } virtual bool can_read_impl() const override { return false; }
bool can_write_impl() const override { return false; } virtual bool can_write_impl() const override { return false; }
bool has_error_impl() const override { return false; } virtual bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override { return false; } virtual bool has_hungup_impl() const override { return false; }
private: private:
BAN::ErrorOr<void> read_mac_address(); BAN::ErrorOr<void> read_mac_address();
@@ -61,7 +61,7 @@ namespace Kernel
void enable_link(); void enable_link();
BAN::ErrorOr<void> enable_interrupt(); BAN::ErrorOr<void> enable_interrupt();
void receive_thread(); void handle_receive();
protected: protected:
PCI::Device& m_pci_device; PCI::Device& m_pci_device;
@@ -75,10 +75,6 @@ namespace Kernel
BAN::UniqPtr<DMARegion> m_tx_descriptor_region; BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
SpinLock m_lock; SpinLock m_lock;
bool m_thread_should_die { false };
BAN::Atomic<bool> m_thread_is_dead { true };
ThreadBlocker m_thread_blocker;
BAN::MACAddress m_mac_address {}; BAN::MACAddress m_mac_address {};
bool m_link_up { false }; bool m_link_up { false };

View File

@@ -12,8 +12,8 @@ namespace Kernel
static BAN::ErrorOr<BAN::RefPtr<E1000E>> create(PCI::Device&); static BAN::ErrorOr<BAN::RefPtr<E1000E>> create(PCI::Device&);
protected: protected:
void detect_eeprom() override; virtual void detect_eeprom() override;
uint32_t eeprom_read(uint8_t addr) override; virtual uint32_t eeprom_read(uint8_t addr) override;
private: private:
E1000E(PCI::Device& pci_device) E1000E(PCI::Device& pci_device)

View File

@@ -38,10 +38,11 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::UniqPtr<IPv4Layer>> create(); static BAN::ErrorOr<BAN::UniqPtr<IPv4Layer>> create();
~IPv4Layer();
ARPTable& arp_table() { return *m_arp_table; } ARPTable& arp_table() { return *m_arp_table; }
BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan); void add_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan);
virtual void unbind_socket(uint16_t port) override; virtual void unbind_socket(uint16_t port) override;
virtual BAN::ErrorOr<void> bind_socket_with_target(BAN::RefPtr<NetworkSocket>, const sockaddr* target_address, socklen_t target_address_len) override; virtual BAN::ErrorOr<void> bind_socket_with_target(BAN::RefPtr<NetworkSocket>, const sockaddr* target_address, socklen_t target_address_len) override;
@@ -54,15 +55,35 @@ namespace Kernel
virtual size_t header_size() const override { return sizeof(IPv4Header); } virtual size_t header_size() const override { return sizeof(IPv4Header); }
private: private:
IPv4Layer() = default; IPv4Layer();
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol) const;
BAN::ErrorOr<in_port_t> find_free_port(); BAN::ErrorOr<in_port_t> find_free_port();
private: void packet_handle_task();
BAN::UniqPtr<ARPTable> m_arp_table; BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ByteSpan);
RecursiveSpinLock m_bound_socket_lock; private:
BAN::HashMap<int, BAN::WeakPtr<NetworkSocket>> m_bound_sockets; struct PendingIPv4Packet
{
NetworkInterface& interface;
};
private:
RecursiveSpinLock m_bound_socket_lock;
BAN::UniqPtr<ARPTable> m_arp_table;
Thread* m_thread { nullptr };
static constexpr size_t pending_packet_buffer_size = 128 * PAGE_SIZE;
BAN::UniqPtr<VirtualRange> m_pending_packet_buffer;
BAN::CircularQueue<PendingIPv4Packet, 128> m_pending_packets;
ThreadBlocker m_pending_thread_blocker;
SpinLock m_pending_lock;
size_t m_pending_total_size { 0 };
BAN::HashMap<int, BAN::WeakPtr<NetworkSocket>> m_bound_sockets;
friend class BAN::UniqPtr<IPv4Layer>; friend class BAN::UniqPtr<IPv4Layer>;
}; };

View File

@@ -9,7 +9,6 @@ namespace Kernel
{ {
public: public:
static constexpr size_t buffer_size = BAN::numeric_limits<uint16_t>::max() + 1; static constexpr size_t buffer_size = BAN::numeric_limits<uint16_t>::max() + 1;
static constexpr size_t buffer_count = 32;
public: public:
static BAN::ErrorOr<BAN::RefPtr<LoopbackInterface>> create(); static BAN::ErrorOr<BAN::RefPtr<LoopbackInterface>> create();
@@ -25,9 +24,8 @@ namespace Kernel
LoopbackInterface() LoopbackInterface()
: NetworkInterface(Type::Loopback) : NetworkInterface(Type::Loopback)
{} {}
~LoopbackInterface();
BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) override; BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override;
bool can_read_impl() const override { return false; } bool can_read_impl() const override { return false; }
bool can_write_impl() const override { return false; } bool can_write_impl() const override { return false; }
@@ -35,27 +33,8 @@ namespace Kernel
bool has_hungup_impl() const override { return false; } bool has_hungup_impl() const override { return false; }
private: private:
void receive_thread(); SpinLock m_buffer_lock;
private:
struct Descriptor
{
uint8_t* addr;
uint32_t size;
uint8_t state;
};
private:
Mutex m_buffer_lock;
BAN::UniqPtr<VirtualRange> m_buffer; BAN::UniqPtr<VirtualRange> m_buffer;
uint32_t m_buffer_tail { 0 };
uint32_t m_buffer_head { 0 };
Descriptor m_descriptors[buffer_count] {};
bool m_thread_should_die { false };
BAN::Atomic<bool> m_thread_is_dead { true };
ThreadBlocker m_thread_blocker;
}; };
} }

View File

@@ -60,11 +60,7 @@ namespace Kernel
virtual dev_t rdev() const override { return m_rdev; } virtual dev_t rdev() const override { return m_rdev; }
virtual BAN::StringView name() const override { return m_name; } virtual BAN::StringView name() const override { return m_name; }
BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan payload) virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) = 0;
{
return send_bytes(destination, protocol, { &payload, 1 });
}
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) = 0;
private: private:
const Type m_type; const Type m_type;

View File

@@ -11,7 +11,7 @@ namespace Kernel
BAN::IPv4Address src_ipv4 { 0 }; BAN::IPv4Address src_ipv4 { 0 };
BAN::IPv4Address dst_ipv4 { 0 }; BAN::IPv4Address dst_ipv4 { 0 };
BAN::NetworkEndian<uint16_t> protocol { 0 }; BAN::NetworkEndian<uint16_t> protocol { 0 };
BAN::NetworkEndian<uint16_t> length { 0 }; BAN::NetworkEndian<uint16_t> extra { 0 };
}; };
static_assert(sizeof(PseudoHeader) == 12); static_assert(sizeof(PseudoHeader) == 12);
@@ -36,7 +36,6 @@ namespace Kernel
NetworkLayer() = default; NetworkLayer() = default;
}; };
uint16_t calculate_internet_checksum(BAN::ConstByteSpan buffer); uint16_t calculate_internet_checksum(BAN::ConstByteSpan packet, const PseudoHeader& pseudo_header);
uint16_t calculate_internet_checksum(BAN::Span<const BAN::ConstByteSpan> buffers);
} }

View File

@@ -32,7 +32,7 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<NetworkInterface>> interface(const sockaddr* target, socklen_t target_len); BAN::ErrorOr<BAN::RefPtr<NetworkInterface>> interface(const sockaddr* target, socklen_t target_len);
virtual size_t protocol_header_size() const = 0; virtual size_t protocol_header_size() const = 0;
virtual void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) = 0; virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) = 0;
virtual NetworkProtocol protocol() const = 0; virtual NetworkProtocol protocol() const = 0;
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) = 0; virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) = 0;

View File

@@ -29,11 +29,9 @@ namespace Kernel
: NetworkInterface(Type::Ethernet) : NetworkInterface(Type::Ethernet)
, m_pci_device(pci_device) , m_pci_device(pci_device)
{ } { }
~RTL8169();
BAN::ErrorOr<void> initialize(); BAN::ErrorOr<void> initialize();
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan>) override; virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override;
virtual bool can_read_impl() const override { return false; } virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; } virtual bool can_write_impl() const override { return false; }
@@ -49,7 +47,7 @@ namespace Kernel
void enable_link(); void enable_link();
BAN::ErrorOr<void> enable_interrupt(); BAN::ErrorOr<void> enable_interrupt();
void receive_thread(); void handle_receive();
protected: protected:
PCI::Device& m_pci_device; PCI::Device& m_pci_device;
@@ -65,9 +63,6 @@ namespace Kernel
BAN::UniqPtr<DMARegion> m_tx_descriptor_region; BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
SpinLock m_lock; SpinLock m_lock;
bool m_thread_should_die { false };
BAN::Atomic<bool> m_thread_is_dead { true };
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
uint32_t m_rx_current { 0 }; uint32_t m_rx_current { 0 };

View File

@@ -4,7 +4,7 @@
#include <BAN/Endianness.h> #include <BAN/Endianness.h>
#include <BAN/Queue.h> #include <BAN/Queue.h>
#include <kernel/Lock/Mutex.h> #include <kernel/Lock/Mutex.h>
#include <kernel/Memory/ByteRingBuffer.h> #include <kernel/Memory/VirtualRange.h>
#include <kernel/Networking/NetworkInterface.h> #include <kernel/Networking/NetworkInterface.h>
#include <kernel/Networking/NetworkSocket.h> #include <kernel/Networking/NetworkSocket.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
@@ -50,30 +50,28 @@ namespace Kernel
static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, const Info&); static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, const Info&);
~TCPSocket(); ~TCPSocket();
NetworkProtocol protocol() const override { return NetworkProtocol::TCP; } virtual NetworkProtocol protocol() const override { return NetworkProtocol::TCP; }
size_t protocol_header_size() const override { return sizeof(TCPHeader) + m_tcp_options_bytes; } virtual size_t protocol_header_size() const override { return sizeof(TCPHeader) + m_tcp_options_bytes; }
void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) override; virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) override;
protected: protected:
BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) override; virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) override;
BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override; virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
BAN::ErrorOr<void> listen_impl(int) override; virtual BAN::ErrorOr<void> listen_impl(int) override;
BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override; virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override; virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override; virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override; virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) override;
BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) override;
BAN::ErrorOr<long> ioctl_impl(int, void*) override; virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override;
void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override; virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
bool can_read_impl() const override; virtual bool can_read_impl() const override;
bool can_write_impl() const override; virtual bool can_write_impl() const override;
bool has_error_impl() const override { return false; } virtual bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override; virtual bool has_hungup_impl() const override;
private: private:
enum class State enum class State
@@ -93,32 +91,33 @@ namespace Kernel
struct RecvWindowInfo struct RecvWindowInfo
{ {
uint32_t start_seq { 0 }; // sequence number of first byte in buffer uint32_t start_seq { 0 }; // sequence number of first byte in buffer
bool has_ghost_byte { false }; bool has_ghost_byte { false };
uint8_t scale_shift { 0 }; // window scale uint32_t data_size { 0 }; // number of bytes in this buffer
BAN::UniqPtr<ByteRingBuffer> buffer; uint8_t scale_shift { 0 }; // window scale
BAN::UniqPtr<VirtualRange> buffer;
}; };
struct SendWindowInfo struct SendWindowInfo
{ {
uint32_t mss { 0 }; // maximum segment size uint32_t mss { 0 }; // maximum segment size
uint16_t non_scaled_size { 0 }; // window size without scaling uint16_t non_scaled_size { 0 }; // window size without scaling
uint8_t scale_shift { 0 }; // window scale uint8_t scale_shift { 0 }; // window scale
uint32_t scaled_size() const { return (uint32_t)non_scaled_size << scale_shift; } uint32_t scaled_size() const { return (uint32_t)non_scaled_size << scale_shift; }
uint32_t start_seq { 0 }; // sequence number of first byte in buffer uint32_t start_seq { 0 }; // sequence number of first byte in buffer
uint32_t current_seq { 0 }; // sequence number of next send uint32_t current_seq { 0 }; // sequence number of next send
uint32_t current_ack { 0 }; // sequence number aknowledged by connection uint32_t current_ack { 0 }; // sequence number aknowledged by connection
uint64_t last_send_ms { 0 }; // last send time, used for retransmission timeout uint64_t last_send_ms { 0 }; // last send time, used for retransmission timeout
bool has_ghost_byte { false }; bool has_ghost_byte { false };
bool had_zero_window { false };
uint32_t sent_size { 0 }; // number of bytes in this buffer that have been sent uint32_t data_size { 0 }; // number of bytes in this buffer
BAN::UniqPtr<ByteRingBuffer> buffer; uint32_t sent_size { 0 }; // number of bytes in this buffer that have been sent
BAN::UniqPtr<VirtualRange> buffer;
}; };
struct ConnectionInfo struct ConnectionInfo
@@ -132,8 +131,6 @@ namespace Kernel
{ {
ConnectionInfo target; ConnectionInfo target;
uint32_t target_start_seq; uint32_t target_start_seq;
uint16_t maximum_seqment_size;
uint8_t window_scale;
}; };
struct ListenKey struct ListenKey
@@ -168,17 +165,8 @@ namespace Kernel
State m_next_state { State::Closed }; State m_next_state { State::Closed };
uint8_t m_next_flags { 0 }; uint8_t m_next_flags { 0 };
size_t m_last_sent_window_size { 0 };
Thread* m_thread { nullptr }; Thread* m_thread { nullptr };
// TODO: actually support these
bool m_keep_alive { false };
bool m_no_delay { false };
bool m_should_send_zero_window { false };
bool m_should_send_window_update { false };
uint64_t m_time_wait_start_ms { 0 }; uint64_t m_time_wait_start_ms { 0 };
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;

View File

@@ -25,28 +25,26 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(NetworkLayer&, const Socket::Info&); static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(NetworkLayer&, const Socket::Info&);
NetworkProtocol protocol() const override { return NetworkProtocol::UDP; } virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; }
size_t protocol_header_size() const override { return sizeof(UDPHeader); } virtual size_t protocol_header_size() const override { return sizeof(UDPHeader); }
void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) override; virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) override;
protected: protected:
void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override; virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override; virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override; virtual BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override;
BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override; virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override; virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); } virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); }
BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) override;
BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) override;
BAN::ErrorOr<long> ioctl_impl(int, void*) override; virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override;
bool can_read_impl() const override { return !m_packets.empty(); } virtual bool can_read_impl() const override { return !m_packets.empty(); }
bool can_write_impl() const override { return true; } virtual bool can_write_impl() const override { return true; }
bool has_error_impl() const override { return false; } virtual bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override { return false; } virtual bool has_hungup_impl() const override { return false; }
private: private:
UDPSocket(NetworkLayer&, const Socket::Info&); UDPSocket(NetworkLayer&, const Socket::Info&);

View File

@@ -6,6 +6,7 @@
#include <kernel/FS/Socket.h> #include <kernel/FS/Socket.h>
#include <kernel/FS/TmpFS/Inode.h> #include <kernel/FS/TmpFS/Inode.h>
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/OpenFileDescriptorSet.h> #include <kernel/OpenFileDescriptorSet.h>
namespace Kernel namespace Kernel
@@ -31,8 +32,6 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override; virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override; virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override; virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) override;
virtual BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) override;
virtual bool can_read_impl() const override; virtual bool can_read_impl() const override;
virtual bool can_write_impl() const override; virtual bool can_write_impl() const override;
@@ -70,10 +69,9 @@ namespace Kernel
size_t size; size_t size;
BAN::Vector<FDWrapper> fds; BAN::Vector<FDWrapper> fds;
BAN::Optional<struct ucred> ucred; BAN::Optional<struct ucred> ucred;
BAN::WeakPtr<UnixDomainSocket> sender;
}; };
BAN::ErrorOr<size_t> add_packet(const msghdr&, PacketInfo&&, bool dont_block); BAN::ErrorOr<void> add_packet(const msghdr&, PacketInfo&&);
private: private:
const Socket::Type m_socket_type; const Socket::Type m_socket_type;
@@ -83,14 +81,10 @@ namespace Kernel
BAN::CircularQueue<PacketInfo, 512> m_packet_infos; BAN::CircularQueue<PacketInfo, 512> m_packet_infos;
size_t m_packet_size_total { 0 }; size_t m_packet_size_total { 0 };
size_t m_packet_buffer_tail { 0 };
BAN::UniqPtr<VirtualRange> m_packet_buffer; BAN::UniqPtr<VirtualRange> m_packet_buffer;
mutable Mutex m_packet_lock; Mutex m_packet_lock;
ThreadBlocker m_packet_thread_blocker; ThreadBlocker m_packet_thread_blocker;
BAN::Atomic<size_t> m_sndbuf { 0 };
BAN::Atomic<size_t> m_bytes_sent { 0 };
friend class BAN::RefPtr<UnixDomainSocket>; friend class BAN::RefPtr<UnixDomainSocket>;
}; };

View File

@@ -44,10 +44,6 @@ namespace Kernel
void close_all(); void close_all();
void close_cloexec(); void close_cloexec();
bool is_cloexec(int fd);
void add_cloexec(int fd);
void remove_cloexec(int fd);
BAN::ErrorOr<void> flock(int fd, int op); BAN::ErrorOr<void> flock(int fd, int op);
BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan); BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan);
@@ -88,6 +84,27 @@ namespace Kernel
friend class BAN::RefPtr<OpenFileDescription>; friend class BAN::RefPtr<OpenFileDescription>;
}; };
struct OpenFile
{
OpenFile() = default;
OpenFile(BAN::RefPtr<OpenFileDescription> description, int descriptor_flags)
: description(BAN::move(description))
, descriptor_flags(descriptor_flags)
{ }
BAN::RefPtr<Inode> inode() const { ASSERT(description); return description->file.inode; }
BAN::StringView path() const { ASSERT(description); return description->file.canonical_path.sv(); }
int& status_flags() { ASSERT(description); return description->status_flags; }
const int& status_flags() const { ASSERT(description); return description->status_flags; }
off_t& offset() { ASSERT(description); return description->offset; }
const off_t& offset() const { ASSERT(description); return description->offset; }
BAN::RefPtr<OpenFileDescription> description;
int descriptor_flags { 0 };
};
BAN::ErrorOr<void> validate_fd(int) const; BAN::ErrorOr<void> validate_fd(int) const;
BAN::ErrorOr<int> get_free_fd() const; BAN::ErrorOr<int> get_free_fd() const;
BAN::ErrorOr<void> get_free_fd_pair(int fds[2]) const; BAN::ErrorOr<void> get_free_fd_pair(int fds[2]) const;
@@ -122,8 +139,7 @@ namespace Kernel
const Credentials& m_credentials; const Credentials& m_credentials;
mutable Mutex m_mutex; mutable Mutex m_mutex;
BAN::Array<BAN::RefPtr<OpenFileDescription>, OPEN_MAX> m_open_files; BAN::Array<OpenFile, OPEN_MAX> m_open_files;
BAN::Array<uint32_t, (OPEN_MAX + 31) / 32> m_cloexec_files {};
}; };
} }

View File

@@ -9,7 +9,6 @@
#include <kernel/ELF.h> #include <kernel/ELF.h>
#include <kernel/FS/Inode.h> #include <kernel/FS/Inode.h>
#include <kernel/Lock/Mutex.h> #include <kernel/Lock/Mutex.h>
#include <kernel/Lock/RWLock.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/MemoryRegion.h> #include <kernel/Memory/MemoryRegion.h>
#include <kernel/Memory/SharedMemoryObject.h> #include <kernel/Memory/SharedMemoryObject.h>
@@ -147,8 +146,6 @@ namespace Kernel
BAN::ErrorOr<long> sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event); BAN::ErrorOr<long> sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
BAN::ErrorOr<long> sys_epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, const struct timespec* timeout, const sigset_t* sigmask); BAN::ErrorOr<long> sys_epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, const struct timespec* timeout, const sigset_t* sigmask);
BAN::ErrorOr<long> sys_eventfd(unsigned int initval_hi, int flags);
BAN::ErrorOr<long> sys_pipe(int fildes[2]); BAN::ErrorOr<long> sys_pipe(int fildes[2]);
BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2); BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2);
@@ -221,6 +218,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_tcgetpgrp(int fd); BAN::ErrorOr<long> sys_tcgetpgrp(int fd);
BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid); BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid);
BAN::ErrorOr<long> sys_termid(char*);
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*); BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*);
BAN::ErrorOr<long> sys_load_keymap(const char* path); BAN::ErrorOr<long> sys_load_keymap(const char* path);
@@ -275,20 +274,17 @@ namespace Kernel
}; };
// Adds new region to the sorted array of mapped regions // Adds new region to the sorted array of mapped regions
// You must hold writer end of m_mapped_region_lock when calling this.
BAN::ErrorOr<void> add_mapped_region(BAN::UniqPtr<MemoryRegion>&&); BAN::ErrorOr<void> add_mapped_region(BAN::UniqPtr<MemoryRegion>&&);
// If address is contained by a region, returns the index of that. // If address is contained by a region, returns the index of that.
// Otherwise returns the address of the first region after this address. // Otherwise returns the address of the first region after this address.
// You must hold reader end of m_mapped_region_lock when calling this.
size_t find_mapped_region(vaddr_t) const; size_t find_mapped_region(vaddr_t) const;
BAN::ErrorOr<VirtualFileSystem::File> find_file(int fd, const char* path, int flags) const; BAN::ErrorOr<VirtualFileSystem::File> find_file(int fd, const char* path, int flags) const;
BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const; BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const;
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const; BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
BAN::ErrorOr<void> read_from_user(const void* user_addr, void* out, size_t size); BAN::ErrorOr<void> validate_string_access(const char*);
BAN::ErrorOr<void> read_string_from_user(const char* user_addr, char* out, size_t max_size); BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write);
BAN::ErrorOr<void> write_to_user(void* user_addr, const void* in, size_t size);
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write); BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
uint64_t signal_pending_mask() const uint64_t signal_pending_mask() const
@@ -333,7 +329,6 @@ namespace Kernel
OpenFileDescriptorSet m_open_file_descriptors; OpenFileDescriptorSet m_open_file_descriptors;
mutable RWLock m_memory_region_lock;
BAN::Vector<BAN::UniqPtr<MemoryRegion>> m_mapped_regions; BAN::Vector<BAN::UniqPtr<MemoryRegion>> m_mapped_regions;
pid_t m_sid; pid_t m_sid;
@@ -351,20 +346,6 @@ namespace Kernel
vaddr_t m_shared_page_vaddr { 0 }; vaddr_t m_shared_page_vaddr { 0 };
struct futex_t
{
Mutex mutex;
ThreadBlocker blocker;
uint32_t waiters { 0 };
uint32_t to_wakeup { 0 };
};
static BAN::HashMap<paddr_t, BAN::UniqPtr<futex_t>> s_futexes;
static Mutex s_futex_lock;
BAN::HashMap<paddr_t, BAN::UniqPtr<futex_t>> m_futexes;
Mutex m_futex_lock;
BAN::Vector<Thread*> m_threads; BAN::Vector<Thread*> m_threads;
struct pthread_info_t struct pthread_info_t
@@ -398,7 +379,6 @@ namespace Kernel
BAN::UniqPtr<PageTable> m_page_table; BAN::UniqPtr<PageTable> m_page_table;
BAN::RefPtr<TTY> m_controlling_terminal; BAN::RefPtr<TTY> m_controlling_terminal;
friend class OpenFileDescriptorSet;
friend class Thread; friend class Thread;
}; };

View File

@@ -46,7 +46,6 @@ namespace Kernel
{ {
uintptr_t vaddr; uintptr_t vaddr;
size_t page_count; size_t page_count;
void* page_table;
} flush_tlb; } flush_tlb;
SchedulerQueue::Node* new_thread; SchedulerQueue::Node* new_thread;
SchedulerQueue::Node* unblock_thread; SchedulerQueue::Node* unblock_thread;
@@ -121,9 +120,6 @@ namespace Kernel
static void update_tsc(); static void update_tsc();
static uint64_t ns_since_boot_tsc(); static uint64_t ns_since_boot_tsc();
static Thread* get_current_sse_thread() { return read_gs_sized<Thread*>(offsetof(Processor, m_sse_thread)); };
static void set_current_sse_thread(Thread* thread) { write_gs_sized<Thread*>(offsetof(Processor, m_sse_thread), thread); };
static paddr_t shared_page_paddr() { return s_shared_page_paddr; } static paddr_t shared_page_paddr() { return s_shared_page_paddr; }
static volatile API::SharedPage& shared_page() { return *reinterpret_cast<API::SharedPage*>(s_shared_page_vaddr); } static volatile API::SharedPage& shared_page() { return *reinterpret_cast<API::SharedPage*>(s_shared_page_vaddr); }
@@ -137,21 +133,6 @@ namespace Kernel
static void load_fsbase(); static void load_fsbase();
static void load_gsbase(); static void load_gsbase();
static void disable_sse()
{
uintptr_t dummy;
#if ARCH(x86_64)
asm volatile("movq %%cr0, %0; orq $0x08, %0; movq %0, %%cr0" : "=r"(dummy));
#elif ARCH(i686)
asm volatile("movl %%cr0, %0; orl $0x08, %0; movl %0, %%cr0" : "=r"(dummy));
#endif
}
static void enable_sse()
{
asm volatile("clts");
}
private: private:
Processor() = default; Processor() = default;
~Processor() { ASSERT_NOT_REACHED(); } ~Processor() { ASSERT_NOT_REACHED(); }
@@ -209,12 +190,10 @@ namespace Kernel
static vaddr_t s_shared_page_vaddr; static vaddr_t s_shared_page_vaddr;
ProcessorID m_id { 0 }; ProcessorID m_id { 0 };
uint8_t m_index { 0 }; uint8_t m_index { 0xFF };
vaddr_t m_thread_syscall_stack; vaddr_t m_thread_syscall_stack;
Thread* m_sse_thread { nullptr };
static constexpr size_t s_stack_size { 4096 }; static constexpr size_t s_stack_size { 4096 };
void* m_stack { nullptr }; void* m_stack { nullptr };

View File

@@ -57,7 +57,7 @@ namespace Kernel
static BAN::ErrorOr<Scheduler*> create(); static BAN::ErrorOr<Scheduler*> create();
BAN::ErrorOr<void> initialize(); BAN::ErrorOr<void> initialize();
void reschedule(YieldRegisters*); void reschedule(InterruptStack*, InterruptRegisters*);
void reschedule_if_idle(); void reschedule_if_idle();
void timer_interrupt(); void timer_interrupt();
@@ -101,7 +101,7 @@ namespace Kernel
InterruptStack* m_interrupt_stack { nullptr }; InterruptStack* m_interrupt_stack { nullptr };
InterruptRegisters* m_interrupt_registers { nullptr }; InterruptRegisters* m_interrupt_registers { nullptr };
uint64_t m_next_reschedule_ns { 0 }; uint64_t m_last_reschedule_ns { 0 };
uint64_t m_last_load_balance_ns { 0 }; uint64_t m_last_load_balance_ns { 0 };
struct ThreadInfo struct ThreadInfo

View File

@@ -3,7 +3,6 @@
#include <BAN/Array.h> #include <BAN/Array.h>
#include <kernel/Device/Device.h> #include <kernel/Device/Device.h>
#include <kernel/Lock/SpinLock.h> #include <kernel/Lock/SpinLock.h>
#include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/Terminal/TerminalDriver.h> #include <kernel/Terminal/TerminalDriver.h>
#include <kernel/ThreadBlocker.h> #include <kernel/ThreadBlocker.h>
#include <LibInput/KeyEvent.h> #include <LibInput/KeyEvent.h>
@@ -103,7 +102,8 @@ namespace Kernel
struct Buffer struct Buffer
{ {
BAN::UniqPtr<ByteRingBuffer> buffer; BAN::Array<uint8_t, 1024> buffer;
size_t bytes { 0 };
bool flush { false }; bool flush { false };
ThreadBlocker thread_blocker; ThreadBlocker thread_blocker;
}; };

View File

@@ -16,7 +16,6 @@
namespace Kernel namespace Kernel
{ {
class MemoryBackedRegion;
class Process; class Process;
class Thread class Thread
@@ -38,12 +37,8 @@ namespace Kernel
// stack overflows on some machines with 8 page stack // stack overflows on some machines with 8 page stack
static constexpr size_t kernel_stack_size { PAGE_SIZE * 16 }; static constexpr size_t kernel_stack_size { PAGE_SIZE * 16 };
// TODO: userspace stack size is hard limited, maybe make this dynamic? // TODO: userspace stack is hard limited to 32 MiB, maybe make this dynamic?
#if ARCH(x86_64)
static constexpr size_t userspace_stack_size { 32 << 20 }; static constexpr size_t userspace_stack_size { 32 << 20 };
#elif ARCH(i686)
static constexpr size_t userspace_stack_size { 4 << 20 };
#endif
public: public:
static BAN::ErrorOr<Thread*> create_kernel(entry_t, void*); static BAN::ErrorOr<Thread*> create_kernel(entry_t, void*);
@@ -60,10 +55,12 @@ namespace Kernel
// Returns true, if thread is going to trigger signal // Returns true, if thread is going to trigger signal
bool is_interrupted_by_signal(bool skip_stop_and_cont = false) const; bool is_interrupted_by_signal(bool skip_stop_and_cont = false) const;
// Returns true if pending signal can be added to thread
bool can_add_signal_to_execute() const;
bool will_execute_signal() const;
// Returns true if handled signal had SA_RESTART // Returns true if handled signal had SA_RESTART
bool handle_signal_if_interrupted(); bool handle_signal(int signal = 0, const siginfo_t& signal_info = {});
bool handle_signal(int signal, const siginfo_t&); void add_signal(int signal, const siginfo_t& info);
void add_signal(int signal, const siginfo_t&);
void set_suspend_signal_mask(uint64_t sigmask); void set_suspend_signal_mask(uint64_t sigmask);
static bool is_stopping_signal(int signal); static bool is_stopping_signal(int signal);
@@ -106,7 +103,9 @@ namespace Kernel
vaddr_t kernel_stack_top() const { return m_kernel_stack->vaddr() + m_kernel_stack->size(); } vaddr_t kernel_stack_top() const { return m_kernel_stack->vaddr() + m_kernel_stack->size(); }
VirtualRange& kernel_stack() { return *m_kernel_stack; } VirtualRange& kernel_stack() { return *m_kernel_stack; }
MemoryBackedRegion& userspace_stack() { ASSERT(is_userspace() && m_userspace_stack); return *m_userspace_stack; } vaddr_t userspace_stack_bottom() const { return is_userspace() ? m_userspace_stack->vaddr() : UINTPTR_MAX; }
vaddr_t userspace_stack_top() const { return is_userspace() ? m_userspace_stack->vaddr() + m_userspace_stack->size() : 0; }
VirtualRange& userspace_stack() { ASSERT(is_userspace()); return *m_userspace_stack; }
static Thread& current(); static Thread& current();
static pid_t current_tid(); static pid_t current_tid();
@@ -130,10 +129,11 @@ namespace Kernel
void set_gsbase(vaddr_t base) { m_gsbase = base; } void set_gsbase(vaddr_t base) { m_gsbase = base; }
vaddr_t get_gsbase() const { return m_gsbase; } vaddr_t get_gsbase() const { return m_gsbase; }
size_t virtual_page_count() const { return m_kernel_stack ? (m_kernel_stack->size() / PAGE_SIZE) : 0; } size_t virtual_page_count() const { return (m_kernel_stack ? (m_kernel_stack->size() / PAGE_SIZE) : 0) + (m_userspace_stack ? (m_userspace_stack->size() / PAGE_SIZE) : 0); }
size_t physical_page_count() const { return virtual_page_count(); } size_t physical_page_count() const { return virtual_page_count(); }
YieldRegisters& yield_registers() { return m_yield_registers; } InterruptStack& interrupt_stack() { return m_interrupt_stack; }
InterruptRegisters& interrupt_registers() { return m_interrupt_registers; }
void save_sse(); void save_sse();
void load_sse(); void load_sse();
@@ -155,37 +155,26 @@ namespace Kernel
bool currently_on_alternate_stack() const; bool currently_on_alternate_stack() const;
struct signal_handle_info_t
{
vaddr_t handler;
vaddr_t stack_top;
uint64_t restore_sigmask;
bool has_sa_restart;
};
signal_handle_info_t remove_signal_and_get_info(int signal);
void handle_signal_impl(int signal, const siginfo_t&, const signal_handle_info_t&);
private: private:
// NOTE: this is the first member to force it being last destructed // NOTE: this is the first member to force it being last destructed
// {kernel,userspace}_stack has to be destroyed before page table // {kernel,userspace}_stack has to be destroyed before page table
BAN::UniqPtr<PageTable> m_keep_alive_page_table; BAN::UniqPtr<PageTable> m_keep_alive_page_table;
BAN::UniqPtr<VirtualRange> m_kernel_stack; BAN::UniqPtr<VirtualRange> m_kernel_stack;
MemoryBackedRegion* m_userspace_stack { nullptr }; BAN::UniqPtr<VirtualRange> m_userspace_stack;
const pid_t m_tid { 0 }; const pid_t m_tid { 0 };
State m_state { State::NotStarted }; State m_state { State::NotStarted };
Process* m_process { nullptr }; Process* m_process { nullptr };
bool m_is_userspace { false }; bool m_is_userspace { false };
bool m_delete_process { false }; bool m_delete_process { false };
bool m_has_custom_fsbase { false };
vaddr_t m_fsbase { 0 }; vaddr_t m_fsbase { 0 };
bool m_has_custom_gsbase { false };
vaddr_t m_gsbase { 0 }; vaddr_t m_gsbase { 0 };
SchedulerQueue::Node* m_scheduler_node { nullptr }; SchedulerQueue::Node* m_scheduler_node { nullptr };
YieldRegisters m_yield_registers { }; InterruptStack m_interrupt_stack { };
InterruptRegisters m_interrupt_registers { };
siginfo_t m_signal_infos[_SIGMAX + 1] { }; siginfo_t m_signal_infos[_SIGMAX + 1] { };
uint64_t m_signal_pending_mask { 0 }; uint64_t m_signal_pending_mask { 0 };

View File

@@ -531,8 +531,11 @@ acpi_release_global_lock:
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EFAULT);
} }
TRY(AML::resolve_package_element(s5_node.as.package->elements[0], true)); if (!s5_node.as.package->elements[0].resolved || !s5_node.as.package->elements[1].resolved)
TRY(AML::resolve_package_element(s5_node.as.package->elements[1], true)); {
dwarnln("TODO: lazy evaluate package \\_S5 elements");
return BAN::Error::from_errno(ENOTSUP);
}
auto slp_typa_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[0].value.node->copy()), AML::ConvInteger, sizeof(uint64_t))); auto slp_typa_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[0].value.node->copy()), AML::ConvInteger, sizeof(uint64_t)));
auto slp_typb_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[1].value.node->copy()), AML::ConvInteger, sizeof(uint64_t))); auto slp_typb_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[1].value.node->copy()), AML::ConvInteger, sizeof(uint64_t)));

View File

@@ -118,8 +118,6 @@ namespace Kernel
BAN::ErrorOr<void> AC97AudioController::initialize() BAN::ErrorOr<void> AC97AudioController::initialize()
{ {
TRY(AudioController::initialize());
m_pci_device.enable_bus_mastering(); m_pci_device.enable_bus_mastering();
m_mixer = TRY(m_pci_device.allocate_bar_region(0)); m_mixer = TRY(m_pci_device.allocate_bar_region(0));
@@ -137,27 +135,8 @@ namespace Kernel
// Reset mixer to default values // Reset mixer to default values
m_mixer->write16(AudioMixerRegister::Reset, 0); m_mixer->write16(AudioMixerRegister::Reset, 0);
// Master volumes // Master volume 100%, no mute
m_mixer->write16(AudioMixerRegister::MasterVolume, 0x2020); m_mixer->write16(AudioMixerRegister::MasterVolume, 0x0000);
if (m_mixer->read16(AudioMixerRegister::MasterVolume) == 0x2020)
{
m_volume_info = {
.min_mdB = -94500,
.max_mdB = 0,
.step_mdB = 1500,
.mdB = 0,
};
}
else
{
m_volume_info = {
.min_mdB = -46500,
.max_mdB = 0,
.step_mdB = 1500,
.mdB = 0,
};
}
m_mixer->write16(AudioMixerRegister::MasterVolume, get_volume_data());
// PCM output volume left/right +0 db, no mute // PCM output volume left/right +0 db, no mute
m_mixer->write16(AudioMixerRegister::PCMOutVolume, 0x0808); m_mixer->write16(AudioMixerRegister::PCMOutVolume, 0x0808);
@@ -206,19 +185,6 @@ namespace Kernel
return {}; return {};
} }
uint32_t AC97AudioController::get_volume_data() const
{
const uint32_t steps = (-m_volume_info.mdB + m_volume_info.step_mdB / 2) / m_volume_info.step_mdB;
return (steps << 8) | steps;
}
BAN::ErrorOr<void> AC97AudioController::set_volume_mdB(int32_t mdB)
{
m_volume_info.mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
m_mixer->write16(AudioMixerRegister::MasterVolume, get_volume_data());
return {};
}
void AC97AudioController::handle_new_data() void AC97AudioController::handle_new_data()
{ {
ASSERT(m_spinlock.current_processor_has_lock()); ASSERT(m_spinlock.current_processor_has_lock());
@@ -237,22 +203,23 @@ namespace Kernel
if (next_bld_head == m_bdl_tail) if (next_bld_head == m_bdl_tail)
break; break;
const size_t sample_frames = BAN::Math::min(m_sample_data->size() / get_channels() / sizeof(uint16_t), m_samples_per_entry / get_channels()); const size_t sample_data_tail = (m_sample_data_head + m_sample_data_capacity - m_sample_data_size) % m_sample_data_capacity;
if (sample_frames == 0)
const size_t max_memcpy = BAN::Math::min(m_sample_data_size, m_sample_data_capacity - sample_data_tail);
const size_t samples = BAN::Math::min(max_memcpy / 2, m_samples_per_entry);
if (samples == 0)
break; break;
const size_t copy_total_bytes = sample_frames * get_channels() * sizeof(uint16_t);
auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[m_bdl_head]; auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[m_bdl_head];
entry.samples = sample_frames * get_channels(); entry.samples = samples;
entry.flags = (1 << 15); entry.flags = (1 << 15);
memcpy( memcpy(
reinterpret_cast<void*>(m_bdl_region->paddr_to_vaddr(entry.address)), reinterpret_cast<void*>(m_bdl_region->paddr_to_vaddr(entry.address)),
m_sample_data->get_data().data(), &m_sample_data[sample_data_tail],
copy_total_bytes samples * 2
); );
m_sample_data->pop(copy_total_bytes); m_sample_data_size -= samples * 2;
lvi = m_bdl_head; lvi = m_bdl_head;
m_bdl_head = next_bld_head; m_bdl_head = next_bld_head;

View File

@@ -53,28 +53,34 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<void> AudioController::initialize()
{
m_sample_data = TRY(ByteRingBuffer::create(m_sample_data_capacity));
return {};
}
BAN::ErrorOr<size_t> AudioController::write_impl(off_t, BAN::ConstByteSpan buffer) BAN::ErrorOr<size_t> AudioController::write_impl(off_t, BAN::ConstByteSpan buffer)
{ {
SpinLockGuard lock_guard(m_spinlock); SpinLockGuard lock_guard(m_spinlock);
while (m_sample_data->full()) while (m_sample_data_size >= m_sample_data_capacity)
{ {
SpinLockGuardAsMutex smutex(lock_guard); SpinLockGuardAsMutex smutex(lock_guard);
TRY(Thread::current().block_or_eintr_indefinite(m_sample_data_blocker, &smutex)); TRY(Thread::current().block_or_eintr_indefinite(m_sample_data_blocker, &smutex));
} }
const size_t to_copy = BAN::Math::min(buffer.size(), m_sample_data->free()); size_t nwritten = 0;
m_sample_data->push(buffer.slice(0, to_copy)); while (nwritten < buffer.size())
{
if (m_sample_data_size >= m_sample_data_capacity)
break;
const size_t max_memcpy = BAN::Math::min(m_sample_data_capacity - m_sample_data_size, m_sample_data_capacity - m_sample_data_head);
const size_t to_copy = BAN::Math::min(buffer.size() - nwritten, max_memcpy);
memcpy(m_sample_data + m_sample_data_head, buffer.data() + nwritten, to_copy);
nwritten += to_copy;
m_sample_data_head = (m_sample_data_head + to_copy) % m_sample_data_capacity;
m_sample_data_size += to_copy;
}
handle_new_data(); handle_new_data();
return to_copy; return nwritten;
} }
BAN::ErrorOr<long> AudioController::ioctl_impl(int cmd, void* arg) BAN::ErrorOr<long> AudioController::ioctl_impl(int cmd, void* arg)
@@ -91,9 +97,9 @@ namespace Kernel
case SND_GET_BUFFERSZ: case SND_GET_BUFFERSZ:
{ {
SpinLockGuard _(m_spinlock); SpinLockGuard _(m_spinlock);
*static_cast<uint32_t*>(arg) = m_sample_data->size(); *static_cast<uint32_t*>(arg) = m_sample_data_size;
if (cmd == SND_RESET_BUFFER) if (cmd == SND_RESET_BUFFER)
m_sample_data->pop(m_sample_data->size()); m_sample_data_size = 0;
return 0; return 0;
} }
case SND_GET_TOTAL_PINS: case SND_GET_TOTAL_PINS:
@@ -105,12 +111,6 @@ namespace Kernel
case SND_SET_PIN: case SND_SET_PIN:
TRY(set_current_pin(*static_cast<uint32_t*>(arg))); TRY(set_current_pin(*static_cast<uint32_t*>(arg)));
return 0; return 0;
case SND_GET_VOLUME_INFO:
*static_cast<snd_volume_info*>(arg) = m_volume_info;
return 0;
case SND_SET_VOLUME_MDB:
TRY(set_volume_mdB(*static_cast<int32_t*>(arg)));
return 0;
} }
return CharacterDevice::ioctl_impl(cmd, arg); return CharacterDevice::ioctl_impl(cmd, arg);

View File

@@ -2,8 +2,6 @@
#include <kernel/Audio/HDAudio/Registers.h> #include <kernel/Audio/HDAudio/Registers.h>
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <BAN/Sort.h>
namespace Kernel namespace Kernel
{ {
@@ -27,8 +25,6 @@ namespace Kernel
BAN::ErrorOr<void> HDAudioFunctionGroup::initialize() BAN::ErrorOr<void> HDAudioFunctionGroup::initialize()
{ {
TRY(AudioController::initialize());
if constexpr(DEBUG_HDAUDIO) if constexpr(DEBUG_HDAUDIO)
{ {
const auto widget_to_string = const auto widget_to_string =
@@ -54,13 +50,19 @@ namespace Kernel
{ {
if (widget.type == HDAudio::AFGWidget::Type::PinComplex) if (widget.type == HDAudio::AFGWidget::Type::PinComplex)
{ {
dprintln(" widget {}: {} ({}, {}, {}), {32b}", const uint32_t config = TRY(m_controller->send_command({
.data = 0x00,
.command = 0xF1C,
.node_index = widget.id,
.codec_address = m_cid,
}));
dprintln(" widget {}: {} ({}, {}), {32b}",
widget.id, widget.id,
widget_to_string(widget.type), widget_to_string(widget.type),
(int)widget.pin_complex.output, (int)widget.pin_complex.output,
(int)widget.pin_complex.input, (int)widget.pin_complex.input,
(int)widget.pin_complex.display, config
widget.pin_complex.config
); );
} }
else else
@@ -77,49 +79,59 @@ namespace Kernel
} }
TRY(initialize_stream()); TRY(initialize_stream());
TRY(initialize_output());
if (auto ret = initialize_output(); ret.is_error())
{
// No usable pins, not really an error
if (ret.error().get_error_code() == ENODEV)
return {};
return ret.release_error();
}
DevFileSystem::get().add_device(this); DevFileSystem::get().add_device(this);
return {}; return {};
} }
uint32_t HDAudioFunctionGroup::get_total_pins() const uint32_t HDAudioFunctionGroup::get_total_pins() const
{ {
return m_output_pins.size(); uint32_t count = 0;
for (const auto& widget : m_afg_node.widgets)
if (widget.type == HDAudio::AFGWidget::Type::PinComplex && widget.pin_complex.output)
count++;
return count;
} }
uint32_t HDAudioFunctionGroup::get_current_pin() const uint32_t HDAudioFunctionGroup::get_current_pin() const
{ {
const auto current_id = m_output_paths[m_output_path_index].front()->id; const auto current_id = m_output_paths[m_output_path_index].front()->id;
for (size_t i = 0; i < m_output_pins.size(); i++)
if (m_output_pins[i]->id == current_id) uint32_t pin = 0;
return i; for (const auto& widget : m_afg_node.widgets)
{
if (widget.type != HDAudio::AFGWidget::Type::PinComplex || !widget.pin_complex.output)
continue;
if (widget.id == current_id)
return pin;
pin++;
}
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
BAN::ErrorOr<void> HDAudioFunctionGroup::set_current_pin(uint32_t pin) BAN::ErrorOr<void> HDAudioFunctionGroup::set_current_pin(uint32_t pin)
{ {
if (pin >= m_output_pins.size()) uint32_t pin_id = 0;
return BAN::Error::from_errno(EINVAL); for (const auto& widget : m_afg_node.widgets)
{
if (widget.type != HDAudio::AFGWidget::Type::PinComplex || !widget.pin_complex.output)
continue;
if (pin-- > 0)
continue;
pin_id = widget.id;
break;
}
if (auto ret = disable_output_path(m_output_path_index); ret.is_error()) if (auto ret = disable_output_path(m_output_path_index); ret.is_error())
dwarnln("failed to disable old output path {}", ret.error()); dwarnln("failed to disable old output path {}", ret.error());
const uint32_t pin_id = m_output_pins[pin]->id;
for (size_t i = 0; i < m_output_paths.size(); i++) for (size_t i = 0; i < m_output_paths.size(); i++)
{ {
if (m_output_paths[i].front()->id != pin_id) if (m_output_paths[i].front()->id != pin_id)
continue; continue;
if (auto ret = enable_output_path(i); ret.is_error()) if (auto ret = enable_output_path(i); !ret.is_error())
{ {
if (ret.error().get_error_code() == ENOTSUP) if (ret.error().get_error_code() == ENOTSUP)
continue; continue;
@@ -127,6 +139,7 @@ namespace Kernel
return ret.release_error(); return ret.release_error();
} }
dprintln("set output widget to {}", pin_id);
m_output_path_index = i; m_output_path_index = i;
return {}; return {};
} }
@@ -136,37 +149,6 @@ namespace Kernel
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
} }
BAN::ErrorOr<void> HDAudioFunctionGroup::set_volume_mdB(int32_t mdB)
{
mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
const auto& path = m_output_paths[m_output_path_index];
for (size_t i = 0; i < path.size(); i++)
{
if (!path[i]->output_amplifier.has_value())
continue;
const int32_t step_round = (mdB >= 0)
? +m_volume_info.step_mdB / 2
: -m_volume_info.step_mdB / 2;
const uint32_t step = (mdB + step_round) / m_volume_info.step_mdB + path[i]->output_amplifier->offset;
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
TRY(m_controller->send_command({
.data = static_cast<uint8_t>(volume & 0xFF),
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
.node_index = path[i]->id,
.codec_address = m_cid,
}));
break;
}
m_volume_info.mdB = mdB;
return {};
}
size_t HDAudioFunctionGroup::bdl_offset() const size_t HDAudioFunctionGroup::bdl_offset() const
{ {
const size_t bdl_entry_bytes = m_bdl_entry_sample_frames * get_channels() * sizeof(uint16_t); const size_t bdl_entry_bytes = m_bdl_entry_sample_frames * get_channels() * sizeof(uint16_t);
@@ -248,39 +230,18 @@ namespace Kernel
BAN::ErrorOr<void> HDAudioFunctionGroup::initialize_output() BAN::ErrorOr<void> HDAudioFunctionGroup::initialize_output()
{ {
BAN::Vector<const HDAudio::AFGWidget*> path;
TRY(path.reserve(m_max_path_length));
for (const auto& widget : m_afg_node.widgets) for (const auto& widget : m_afg_node.widgets)
{ {
if (widget.type != HDAudio::AFGWidget::Type::PinComplex || !widget.pin_complex.output) if (widget.type != HDAudio::AFGWidget::Type::PinComplex || !widget.pin_complex.output)
continue; continue;
// no physical connection
if ((widget.pin_complex.config >> 30) == 0b01)
continue;
// needs a GPU
if (widget.pin_complex.display)
continue;
BAN::Vector<const HDAudio::AFGWidget*> path;
TRY(path.push_back(&widget)); TRY(path.push_back(&widget));
TRY(recurse_output_paths(widget, path)); TRY(recurse_output_paths(widget, path));
path.pop_back();
if (!m_output_paths.empty() && m_output_paths.back().front()->id == widget.id)
TRY(m_output_pins.push_back(&widget));
} }
if (m_output_pins.empty())
return BAN::Error::from_errno(ENODEV);
// prefer short paths
BAN::sort::sort(m_output_paths.begin(), m_output_paths.end(),
[](const auto& a, const auto& b) {
if (a.front()->id != b.front()->id)
return a.front()->id < b.front()->id;
return a.size() < b.size();
}
);
dprintln_if(DEBUG_HDAUDIO, "found {} paths from output to DAC", m_output_paths.size()); dprintln_if(DEBUG_HDAUDIO, "found {} paths from output to DAC", m_output_paths.size());
// select first supported path // select first supported path
@@ -322,6 +283,13 @@ namespace Kernel
return 0b0'0'000'000'0'001'0001; return 0b0'0'000'000'0'001'0001;
} }
uint16_t HDAudioFunctionGroup::get_volume_data() const
{
// TODO: don't hardcode this
// left and right output, no mute, max gain
return 0b1'0'1'1'0000'0'1111111;
}
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index) BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
{ {
ASSERT(index < m_output_paths.size()); ASSERT(index < m_output_paths.size());
@@ -342,6 +310,7 @@ namespace Kernel
} }
const auto format = get_format_data(); const auto format = get_format_data();
const auto volume = get_volume_data();
for (size_t i = 0; i < path.size(); i++) for (size_t i = 0; i < path.size(); i++)
{ {
@@ -370,17 +339,13 @@ namespace Kernel
})); }));
} }
// set volume to 0 dB, no mute // set volume
if (path[i]->output_amplifier.has_value()) TRY(m_controller->send_command({
{ .data = static_cast<uint8_t>(volume & 0xFF),
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | path[i]->output_amplifier->offset; .command = static_cast<uint16_t>(0x300 | (volume >> 8)),
TRY(m_controller->send_command({ .node_index = path[i]->id,
.data = static_cast<uint8_t>(volume & 0xFF), .codec_address = m_cid,
.command = static_cast<uint16_t>(0x300 | (volume >> 8)), }));
.node_index = path[i]->id,
.codec_address = m_cid,
}));
}
switch (path[i]->type) switch (path[i]->type)
{ {
@@ -425,41 +390,6 @@ namespace Kernel
} }
} }
// update volume info to this path
m_volume_info.min_mdB = 0;
m_volume_info.max_mdB = 0;
m_volume_info.step_mdB = 0;
for (size_t i = 0; i < path.size(); i++)
{
if (!path[i]->output_amplifier.has_value())
continue;
const auto& amp = path[i]->output_amplifier.value();
const int32_t step_mdB = amp.step_size * 250;
m_volume_info.step_mdB = step_mdB;
m_volume_info.min_mdB = -amp.offset * step_mdB;
m_volume_info.max_mdB = (amp.num_steps - amp.offset) * step_mdB;
m_volume_info.mdB = BAN::Math::clamp(m_volume_info.mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
const int32_t step_round = (m_volume_info.mdB >= 0)
? +step_mdB / 2
: -step_mdB / 2;
const uint32_t step = (m_volume_info.mdB + step_round) / step_mdB + amp.offset;
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
TRY(m_controller->send_command({
.data = static_cast<uint8_t>(volume & 0xFF),
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
.node_index = path[i]->id,
.codec_address = m_cid,
}));
break;
}
if (m_volume_info.min_mdB == 0 && m_volume_info.max_mdB == 0)
m_volume_info.mdB = 0;
return {}; return {};
} }
@@ -512,6 +442,10 @@ namespace Kernel
BAN::ErrorOr<void> HDAudioFunctionGroup::recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path) BAN::ErrorOr<void> HDAudioFunctionGroup::recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path)
{ {
// cycle "detection"
if (path.size() >= m_max_path_length)
return {};
// we've reached a DAC // we've reached a DAC
if (widget.type == HDAudio::AFGWidget::Type::OutputConverter) if (widget.type == HDAudio::AFGWidget::Type::OutputConverter)
{ {
@@ -528,18 +462,9 @@ namespace Kernel
{ {
if (!widget.connections.contains(connection.id)) if (!widget.connections.contains(connection.id))
continue; continue;
// cycle detection
for (const auto* w : path)
if (w == &connection)
goto already_visited;
TRY(path.push_back(&connection)); TRY(path.push_back(&connection));
TRY(recurse_output_paths(connection, path)); TRY(recurse_output_paths(connection, path));
path.pop_back(); path.pop_back();
already_visited:
continue;
} }
return {}; return {};
@@ -558,18 +483,30 @@ namespace Kernel
while ((m_bdl_head + 1) % m_bdl_entry_count != m_bdl_tail) while ((m_bdl_head + 1) % m_bdl_entry_count != m_bdl_tail)
{ {
const size_t sample_frames = BAN::Math::min(m_sample_data->size() / get_channels() / sizeof(uint16_t), m_bdl_entry_sample_frames); const size_t sample_data_tail = (m_sample_data_head + m_sample_data_capacity - m_sample_data_size) % m_sample_data_capacity;
const size_t sample_frames = BAN::Math::min(m_sample_data_size / get_channels() / sizeof(uint16_t), m_bdl_entry_sample_frames);
if (sample_frames == 0) if (sample_frames == 0)
break; break;
const size_t copy_total_bytes = sample_frames * get_channels() * sizeof(uint16_t); const size_t copy_total_bytes = sample_frames * get_channels() * sizeof(uint16_t);
const size_t copy_before_wrap = BAN::Math::min(copy_total_bytes, m_sample_data_capacity - sample_data_tail);
memcpy( memcpy(
reinterpret_cast<void*>(m_bdl_region->vaddr() + m_bdl_head * bdl_entry_bytes), reinterpret_cast<void*>(m_bdl_region->vaddr() + m_bdl_head * bdl_entry_bytes),
m_sample_data->get_data().data(), &m_sample_data[sample_data_tail],
copy_total_bytes copy_before_wrap
); );
if (copy_before_wrap < copy_total_bytes)
{
memcpy(
reinterpret_cast<void*>(m_bdl_region->vaddr() + m_bdl_head * bdl_entry_bytes + copy_before_wrap),
&m_sample_data[0],
copy_total_bytes - copy_before_wrap
);
}
if (copy_total_bytes < bdl_entry_bytes) if (copy_total_bytes < bdl_entry_bytes)
{ {
memset( memset(
@@ -579,7 +516,8 @@ namespace Kernel
); );
} }
m_sample_data->pop(copy_total_bytes); m_sample_data_size -= copy_total_bytes;
m_bdl_head = (m_bdl_head + 1) % m_bdl_entry_count; m_bdl_head = (m_bdl_head + 1) % m_bdl_entry_count;
} }

View File

@@ -65,12 +65,8 @@ namespace Kernel
m_pci_device.enable_interrupt(0, *this); m_pci_device.enable_interrupt(0, *this);
m_bar0->write32(Regs::INTCTL, UINT32_MAX); m_bar0->write32(Regs::INTCTL, UINT32_MAX);
const uint16_t state_sts = m_bar0->read16(Regs::STATESTS); for (uint8_t codec_id = 0; codec_id < 0x10; codec_id++)
for (uint8_t codec_id = 0; codec_id < 15; codec_id++)
{ {
if (!(state_sts & (1 << codec_id)))
continue;
auto codec_or_error = initialize_codec(codec_id); auto codec_or_error = initialize_codec(codec_id);
if (codec_or_error.is_error()) if (codec_or_error.is_error())
continue; continue;
@@ -311,26 +307,8 @@ namespace Kernel
if (result.type == AFGWidget::Type::PinComplex) if (result.type == AFGWidget::Type::PinComplex)
{ {
const uint32_t cap = send_command_or_zero(0xF00, 0x0C); const uint32_t cap = send_command_or_zero(0xF00, 0x0C);
result.pin_complex = { result.pin_complex.output = !!(cap & (1 << 4));
.input = !!(cap & (1 << 5)), result.pin_complex.input = !!(cap & (1 << 5));
.output = !!(cap & (1 << 4)),
.display = !!(cap & ((1 << 7) | (1 << 24))),
.config = send_command_or_zero(0xF1C, 0x00),
};
}
if (const uint32_t out_amp_cap = send_command_or_zero(0xF00, 0x12))
{
const uint8_t offset = (out_amp_cap >> 0) & 0x7F;
const uint8_t num_steps = (out_amp_cap >> 8) & 0x7F;
const uint8_t step_size = (out_amp_cap >> 16) & 0x7F;
const bool mute = (out_amp_cap >> 31);
result.output_amplifier = HDAudio::AFGWidget::Amplifier {
.offset = offset,
.num_steps = num_steps,
.step_size = step_size,
.mute = mute,
};
} }
const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E); const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E);

View File

@@ -29,33 +29,28 @@ namespace Debug
static uint8_t s_debug_ansi_state { 0 }; static uint8_t s_debug_ansi_state { 0 };
void dump_stack_trace() void dump_stack_trace()
{
dump_stack_trace(0, reinterpret_cast<uintptr_t>(__builtin_frame_address(0)));
}
void dump_stack_trace(uintptr_t ip, uintptr_t bp)
{ {
using namespace Kernel; using namespace Kernel;
struct stackframe struct stackframe
{ {
stackframe* bp; stackframe* bp;
void* ip; uintptr_t ip;
}; };
SpinLockGuard _(s_debug_lock); SpinLockGuard _(s_debug_lock);
const stackframe* frame = reinterpret_cast<const stackframe*>(bp); stackframe* frame = (stackframe*)__builtin_frame_address(0);
if (!frame)
void* first_ip = frame->ip; {
void* last_ip = 0; dprintln("Could not get frame address");
return;
}
uintptr_t first_ip = frame->ip;
uintptr_t last_ip = 0;
bool first = true; bool first = true;
BAN::Formatter::print(Debug::putchar, "\e[36mStack trace:\r\n"); BAN::Formatter::print(Debug::putchar, "\e[36mStack trace:\r\n");
if (ip != 0)
BAN::Formatter::print(Debug::putchar, " {}\r\n", reinterpret_cast<void*>(ip));
while (frame) while (frame)
{ {
if (!PageTable::is_valid_pointer((vaddr_t)frame)) if (!PageTable::is_valid_pointer((vaddr_t)frame))
@@ -335,8 +330,6 @@ namespace Debug
void print_prefix(const char* file, int line) void print_prefix(const char* file, int line)
{ {
if (file[0] == '.' && file[1] == '/')
file += 2;
auto ms_since_boot = Kernel::SystemTimer::is_initialized() ? Kernel::SystemTimer::get().ms_since_boot() : 0; auto ms_since_boot = Kernel::SystemTimer::is_initialized() ? Kernel::SystemTimer::get().ms_since_boot() : 0;
BAN::Formatter::print(Debug::putchar, "[{5}.{3}] {}:{}: ", ms_since_boot / 1000, ms_since_boot % 1000, file, line); BAN::Formatter::print(Debug::putchar, "[{5}.{3}] {}:{}: ", ms_since_boot / 1000, ms_since_boot % 1000, file, line);
} }

View File

@@ -21,11 +21,10 @@ namespace Kernel
{ {
auto ms_since_boot = SystemTimer::get().ms_since_boot(); auto ms_since_boot = SystemTimer::get().ms_since_boot();
SpinLockGuard _(Debug::s_debug_lock); SpinLockGuard _(Debug::s_debug_lock);
BAN::Formatter::print(Debug::putchar, "[{5}.{3}] {}:{} {}: ", BAN::Formatter::print(Debug::putchar, "[{5}.{3}] {} {}: ",
ms_since_boot / 1000, ms_since_boot / 1000,
ms_since_boot % 1000, ms_since_boot % 1000,
Kernel::Process::current().pid(), Kernel::Process::current().pid(),
Thread::current().tid(),
Kernel::Process::current().name() Kernel::Process::current().name()
); );
for (size_t i = 0; i < buffer.size(); i++) for (size_t i = 0; i < buffer.size(); i++)

View File

@@ -6,7 +6,6 @@
#include <kernel/Terminal/FramebufferTerminal.h> #include <kernel/Terminal/FramebufferTerminal.h>
#include <sys/framebuffer.h> #include <sys/framebuffer.h>
#include <sys/ioctl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
@@ -134,26 +133,6 @@ namespace Kernel
return bytes_to_copy; return bytes_to_copy;
} }
BAN::ErrorOr<long> FramebufferDevice::ioctl_impl(int cmd, void* arg)
{
switch (cmd)
{
case FB_MSYNC_RECTANGLE:
{
auto& rectangle = *static_cast<fb_msync_region*>(arg);
sync_pixels_rectangle(
rectangle.min_x,
rectangle.min_y,
rectangle.max_x - rectangle.min_x,
rectangle.max_y - rectangle.min_y
);
return 0;
}
}
return CharacterDevice::ioctl(cmd, arg);
}
uint32_t FramebufferDevice::get_pixel(uint32_t x, uint32_t y) const uint32_t FramebufferDevice::get_pixel(uint32_t x, uint32_t y) const
{ {
ASSERT(x < m_width && y < m_height); ASSERT(x < m_width && y < m_height);

View File

@@ -128,18 +128,16 @@ namespace Kernel
{ {
auto& [inode, events] = *it; auto& [inode, events] = *it;
#define REMOVE_IT() \ #define REMOVE_IT_AND_CONTINUE() \
({ \ ({ \
m_processing_events.remove(it); \ m_processing_events.remove(it); \
if (event_count > 0) \
break; \
it = m_processing_events.begin(); \ it = m_processing_events.begin(); \
continue; \ continue; \
}) })
auto listen_it = m_listening_events.find(inode); auto listen_it = m_listening_events.find(inode);
if (listen_it == m_listening_events.end()) if (listen_it == m_listening_events.end())
REMOVE_IT(); REMOVE_IT_AND_CONTINUE();
auto& listen = listen_it->value; auto& listen = listen_it->value;
{ {
@@ -151,7 +149,7 @@ namespace Kernel
} }
if (events == 0) if (events == 0)
REMOVE_IT(); REMOVE_IT_AND_CONTINUE();
{ {
LockGuard inode_locker(inode->m_mutex); LockGuard inode_locker(inode->m_mutex);
@@ -167,9 +165,9 @@ namespace Kernel
} }
if (events == 0) if (events == 0)
REMOVE_IT(); REMOVE_IT_AND_CONTINUE();
#undef REMOVE_IT #undef REMOVE_IT_AND_CONTINUE
for (size_t fd = 0; fd < listen.events.size() && event_count < event_span.size(); fd++) for (size_t fd = 0; fd < listen.events.size() && event_count < event_span.size(); fd++)
{ {
@@ -209,7 +207,7 @@ namespace Kernel
continue; continue;
SpinLockGuardAsMutex smutex(guard); SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_or_waketime_ns(m_thread_blocker, waketime_ns, false, &smutex)); TRY(Thread::current().block_or_eintr_or_timeout_ns(m_thread_blocker, waketime_ns - current_ns, false, &smutex));
} }
return event_count; return event_count;

View File

@@ -1,54 +0,0 @@
#include <kernel/FS/EventFD.h>
#include <sys/epoll.h>
namespace Kernel
{
BAN::ErrorOr<BAN::RefPtr<Inode>> EventFD::create(uint64_t initval, bool semaphore)
{
auto* eventfd_ptr = new EventFD(initval, semaphore);
if (eventfd_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<Inode>(BAN::RefPtr<EventFD>::adopt(eventfd_ptr));
}
BAN::ErrorOr<size_t> EventFD::read_impl(off_t, BAN::ByteSpan buffer)
{
if (buffer.size() < sizeof(uint64_t))
return BAN::Error::from_errno(EINVAL);
while (m_value == 0)
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
const uint64_t read_value = m_is_semaphore ? 1 : m_value;
m_value -= read_value;
buffer.as<uint64_t>() = read_value;
epoll_notify(EPOLLOUT);
return sizeof(uint64_t);
}
BAN::ErrorOr<size_t> EventFD::write_impl(off_t, BAN::ConstByteSpan buffer)
{
if (buffer.size() < sizeof(uint64_t))
return BAN::Error::from_errno(EINVAL);
const uint64_t write_value = buffer.as<const uint64_t>();
if (write_value == UINT64_MAX)
return BAN::Error::from_errno(EINVAL);
while (m_value + write_value < m_value)
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
m_value += write_value;
if (m_value > 0)
epoll_notify(EPOLLIN);
return sizeof(uint64_t);
}
}

View File

@@ -1,5 +1,4 @@
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
#include <BAN/Sort.h>
#include <kernel/FS/Ext2/FileSystem.h> #include <kernel/FS/Ext2/FileSystem.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
@@ -128,7 +127,7 @@ namespace Kernel
{ {
auto block_buffer = TRY(m_buffer_manager.get_buffer()); auto block_buffer = TRY(m_buffer_manager.get_buffer());
if ((superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) || !(m_superblock.feature_ro_compat & Ext2::Enum::FEATURE_RO_COMPAT_SPARSE_SUPER)) if (superblock().rev_level == Ext2::Enum::GOOD_OLD_REV)
{ {
// In revision 0 all blockgroups contain superblock backup // In revision 0 all blockgroups contain superblock backup
TRY(m_superblock_backups.reserve(number_of_block_groups - 1)); TRY(m_superblock_backups.reserve(number_of_block_groups - 1));
@@ -149,8 +148,6 @@ namespace Kernel
// We don't really care if this succeeds or not // We don't really care if this succeeds or not
(void)m_superblock_backups.shrink_to_fit(); (void)m_superblock_backups.shrink_to_fit();
BAN::sort::sort(m_superblock_backups.begin(), m_superblock_backups.end());
} }
for (uint32_t bg : m_superblock_backups) for (uint32_t bg : m_superblock_backups)
@@ -491,7 +488,14 @@ namespace Kernel
TRY(read_block(bgd_location.block, bgd_buffer)); TRY(read_block(bgd_location.block, bgd_buffer));
const auto bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>(); auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
const uint32_t inode_byte_offset = inode_index * superblock().inode_size;
BlockLocation location
{
.block = inode_byte_offset / block_size + bgd.inode_table,
.offset = inode_byte_offset % block_size
};
#if EXT2_VERIFY_INODE #if EXT2_VERIFY_INODE
const uint32_t inode_bitmap_block = bgd.inode_bitmap; const uint32_t inode_bitmap_block = bgd.inode_bitmap;
@@ -499,18 +503,14 @@ namespace Kernel
// NOTE: we can reuse the bgd_buffer since it is not needed anymore // NOTE: we can reuse the bgd_buffer since it is not needed anymore
auto& inode_bitmap = bgd_buffer; auto& inode_bitmap = bgd_buffer;
TRY(read_block(inode_bitmap_block, inode_bitmap)); read_block(inode_bitmap_block, inode_bitmap.span());
const uint32_t byte = inode_index / 8; const uint32_t byte = inode_index / 8;
const uint32_t bit = inode_index % 8; const uint32_t bit = inode_index % 8;
ASSERT(inode_bitmap[byte] & (1 << bit)); ASSERT(inode_bitmap[byte] & (1 << bit));
#endif #endif
const uint32_t inode_byte_offset = inode_index * superblock().inode_size; return location;
return BlockLocation {
.block = inode_byte_offset / block_size + bgd.inode_table,
.offset = inode_byte_offset % block_size
};
} }
Ext2FS::BlockLocation Ext2FS::locate_block_group_descriptior(uint32_t group_index) Ext2FS::BlockLocation Ext2FS::locate_block_group_descriptior(uint32_t group_index)
@@ -525,94 +525,29 @@ namespace Kernel
// Block Group Descriptor table is in the block after superblock // Block Group Descriptor table is in the block after superblock
const uint32_t bgd_byte_offset = (superblock().first_data_block + 1) * block_size + sizeof(Ext2::BlockGroupDescriptor) * group_index; const uint32_t bgd_byte_offset = (superblock().first_data_block + 1) * block_size + sizeof(Ext2::BlockGroupDescriptor) * group_index;
return BlockLocation { return
{
.block = bgd_byte_offset / block_size, .block = bgd_byte_offset / block_size,
.offset = bgd_byte_offset % block_size .offset = bgd_byte_offset % block_size
}; };
} }
void Ext2FS::BlockBufferManager::destroy_callback(const uint8_t* buffer_ptr)
{
const auto tid = Thread::current_tid();
LockGuard _(m_buffer_mutex);
for (auto& buffer : m_buffers)
{
if (buffer.buffer.data() != buffer_ptr)
continue;
ASSERT(buffer.used);
buffer.used = false;
break;
}
for (auto& info : m_thread_infos)
{
if (info.tid != tid)
continue;
ASSERT(info.buffers > 0);
info.buffers--;
if (info.buffers != 0)
break;
info.tid = 0;
m_buffer_blocker.unblock();
break;
}
}
BAN::ErrorOr<Ext2FS::BlockBufferWrapper> Ext2FS::BlockBufferManager::get_buffer() BAN::ErrorOr<Ext2FS::BlockBufferWrapper> Ext2FS::BlockBufferManager::get_buffer()
{ {
const auto tid = Thread::current_tid();
ASSERT(tid);
LockGuard _(m_buffer_mutex); LockGuard _(m_buffer_mutex);
ThreadInfo* thread_info = nullptr; for (;;)
for (auto& info : m_thread_infos)
{ {
if (info.tid != tid) for (auto& buffer : m_buffers)
continue;
thread_info = &info;
break;
}
while (thread_info == nullptr)
{
for (auto& info : m_thread_infos)
{ {
if (info.tid != 0) if (buffer.used)
continue; continue;
thread_info = &info; buffer.used = true;
break; return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), &buffer.used, &m_buffer_mutex, &m_buffer_blocker);
}
if (thread_info)
{
thread_info->tid = tid;
thread_info->buffers = 0;
break;
} }
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &m_buffer_mutex)); TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &m_buffer_mutex));
} }
ASSERT(thread_info->buffers < max_buffers_per_thread);
thread_info->buffers++;
for (auto& buffer : m_buffers)
{
if (buffer.used)
continue;
buffer.used = true;
return Ext2FS::BlockBufferWrapper {
buffer.buffer.span(),
[](void* self, const uint8_t* buffer) { static_cast<BlockBufferManager*>(self)->destroy_callback(buffer); },
this
};
}
ASSERT_NOT_REACHED();
} }
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size) BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)

View File

@@ -61,13 +61,13 @@ namespace Kernel
const uint32_t inode_blocks_per_fs_block = blksize() / 512; const uint32_t inode_blocks_per_fs_block = blksize() / 512;
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t); const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
if (block == 0 && !allocate)
return BAN::Optional<uint32_t>();
if (depth == 0) if (depth == 0)
{ {
if (block == 0) if (block == 0)
{ {
if (!allocate)
return BAN::Optional<uint32_t>();
block = TRY(m_fs.reserve_free_block(block_group())); block = TRY(m_fs.reserve_free_block(block_group()));
m_inode.blocks += inode_blocks_per_fs_block; m_inode.blocks += inode_blocks_per_fs_block;
@@ -87,6 +87,9 @@ namespace Kernel
TRY(m_fs.read_block(block, block_buffer)); TRY(m_fs.read_block(block, block_buffer));
else else
{ {
if (!allocate)
return BAN::Optional<uint32_t>();
block = TRY(m_fs.reserve_free_block(block_group())); block = TRY(m_fs.reserve_free_block(block_group()));
m_inode.blocks += inode_blocks_per_fs_block; m_inode.blocks += inode_blocks_per_fs_block;
@@ -168,10 +171,8 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::set_link_target_impl(BAN::StringView target) BAN::ErrorOr<void> Ext2Inode::set_link_target_impl(BAN::StringView target)
{ {
ASSERT(mode().iflnk()); ASSERT(mode().iflnk());
if (target.size() < sizeof(m_inode.block)) if (m_inode.size < sizeof(m_inode.block) && target.size() < sizeof(m_inode.block))
{ {
if (m_inode.size >= sizeof(m_inode.block))
TRY(cleanup_data_blocks());
memset(m_inode.block, 0, sizeof(m_inode.block)); memset(m_inode.block, 0, sizeof(m_inode.block));
memcpy(m_inode.block, target.data(), target.size()); memcpy(m_inode.block, target.data(), target.size());
m_inode.size = target.size(); m_inode.size = target.size();
@@ -411,8 +412,10 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<void> Ext2Inode::cleanup_data_blocks() BAN::ErrorOr<void> Ext2Inode::cleanup_from_fs()
{ {
ASSERT(m_inode.links_count == 0);
if (mode().iflnk() && (size_t)size() < sizeof(m_inode.block)) if (mode().iflnk() && (size_t)size() < sizeof(m_inode.block))
goto done; goto done;
@@ -433,16 +436,12 @@ done:
// mark blocks as deleted // mark blocks as deleted
memset(m_inode.block, 0x00, sizeof(m_inode.block)); memset(m_inode.block, 0x00, sizeof(m_inode.block));
// FIXME: this is only required since fs does not get
// deleting inode from its cache
TRY(sync()); TRY(sync());
return {};
}
BAN::ErrorOr<void> Ext2Inode::cleanup_from_fs()
{
ASSERT(m_inode.links_count == 0);
TRY(cleanup_data_blocks());
TRY(m_fs.delete_inode(ino())); TRY(m_fs.delete_inode(ino()));
return {}; return {};
} }

View File

@@ -222,22 +222,6 @@ namespace Kernel
return getpeername_impl(address, address_len); return getpeername_impl(address, address_len);
} }
BAN::ErrorOr<void> Inode::getsockopt(int level, int option, void* value, socklen_t* value_len)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return getsockopt_impl(level, option, value, value_len);
}
BAN::ErrorOr<void> Inode::setsockopt(int level, int option, const void* value, socklen_t value_len)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return setsockopt_impl(level, option, value, value_len);
}
BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer)
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);

View File

@@ -9,16 +9,12 @@
namespace Kernel namespace Kernel
{ {
static constexpr size_t s_pipe_buffer_size = 0x10000;
BAN::ErrorOr<BAN::RefPtr<Inode>> Pipe::create(const Credentials& credentials) BAN::ErrorOr<BAN::RefPtr<Inode>> Pipe::create(const Credentials& credentials)
{ {
auto* pipe_ptr = new Pipe(credentials); Pipe* pipe = new Pipe(credentials);
if (pipe_ptr == nullptr) if (pipe == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto pipe = BAN::RefPtr<Pipe>::adopt(pipe_ptr); return BAN::RefPtr<Inode>::adopt(pipe);
pipe->m_buffer = TRY(ByteRingBuffer::create(s_pipe_buffer_size));
return BAN::RefPtr<Inode>(pipe);
} }
Pipe::Pipe(const Credentials& credentials) Pipe::Pipe(const Credentials& credentials)
@@ -73,16 +69,27 @@ namespace Kernel
BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer)
{ {
while (m_buffer->empty()) while (m_buffer_size == 0)
{ {
if (m_writing_count == 0) if (m_writing_count == 0)
return 0; return 0;
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
} }
const size_t to_copy = BAN::Math::min<size_t>(buffer.size(), m_buffer->size()); const size_t to_copy = BAN::Math::min<size_t>(buffer.size(), m_buffer_size);
memcpy(buffer.data(), m_buffer->get_data().data(), to_copy);
m_buffer->pop(to_copy); if (m_buffer_tail + to_copy <= m_buffer.size())
memcpy(buffer.data(), m_buffer.data() + m_buffer_tail, to_copy);
else
{
const size_t before_wrap = m_buffer.size() - m_buffer_tail;
const size_t after_wrap = to_copy - before_wrap;
memcpy(buffer.data(), m_buffer.data() + m_buffer_tail, before_wrap);
memcpy(buffer.data() + before_wrap, m_buffer.data(), after_wrap);
}
m_buffer_tail = (m_buffer_tail + to_copy) % m_buffer.size();
m_buffer_size -= to_copy;
m_atime = SystemTimer::get().real_time(); m_atime = SystemTimer::get().real_time();
@@ -95,7 +102,7 @@ namespace Kernel
BAN::ErrorOr<size_t> Pipe::write_impl(off_t, BAN::ConstByteSpan buffer) BAN::ErrorOr<size_t> Pipe::write_impl(off_t, BAN::ConstByteSpan buffer)
{ {
while (m_buffer->full()) while (m_buffer_size >= m_buffer.size())
{ {
if (m_reading_count == 0) if (m_reading_count == 0)
{ {
@@ -105,8 +112,20 @@ namespace Kernel
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
} }
const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer->free()); const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer.size() - m_buffer_size);
m_buffer->push(buffer.slice(0, to_copy)); const size_t buffer_head = (m_buffer_tail + m_buffer_size) % m_buffer.size();
if (buffer_head + to_copy <= m_buffer.size())
memcpy(m_buffer.data() + buffer_head, buffer.data(), to_copy);
else
{
const size_t before_wrap = m_buffer.size() - buffer_head;
const size_t after_wrap = to_copy - before_wrap;
memcpy(m_buffer.data() + buffer_head, buffer.data(), before_wrap);
memcpy(m_buffer.data(), buffer.data() + before_wrap, after_wrap);
}
m_buffer_size += to_copy;
timespec current_time = SystemTimer::get().real_time(); timespec current_time = SystemTimer::get().real_time();
m_mtime = current_time; m_mtime = current_time;

View File

@@ -1,262 +1,94 @@
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
#include <kernel/FS/USTARModule.h> #include <kernel/FS/USTARModule.h>
#include <kernel/Timer/Timer.h>
#include <LibDEFLATE/Decompressor.h>
#include <tar.h> #include <tar.h>
namespace Kernel namespace Kernel
{ {
class DataSource bool is_ustar_boot_module(const BootModule& module)
{ {
public: if (module.start % PAGE_SIZE)
DataSource() = default;
virtual ~DataSource() = default;
size_t data_size() const
{ {
return m_data_size; dprintln("ignoring non-page-aligned module");
}
BAN::ConstByteSpan data()
{
return { m_data_buffer, m_data_size };
}
void pop_data(size_t size)
{
ASSERT(size <= m_data_size);
if (size > 0 && size < m_data_size)
memmove(m_data_buffer, m_data_buffer + size, m_data_size - size);
m_data_size -= size;
m_bytes_produced += size;
}
virtual BAN::ErrorOr<bool> produce_data() = 0;
uint64_t bytes_produced() const
{
return m_bytes_produced;
}
virtual uint64_t bytes_consumed() const = 0;
protected:
uint8_t m_data_buffer[4096];
size_t m_data_size { 0 };
private:
uint64_t m_bytes_produced { 0 };
};
class DataSourceRaw final : public DataSource
{
public:
DataSourceRaw(const BootModule& module)
: m_module(module)
{ }
BAN::ErrorOr<bool> produce_data() override
{
if (m_offset >= m_module.size || m_data_size >= sizeof(m_data_buffer))
return false;
while (m_offset < m_module.size && m_data_size < sizeof(m_data_buffer))
{
const size_t to_copy = BAN::Math::min(
sizeof(m_data_buffer) - m_data_size,
PAGE_SIZE - (m_offset % PAGE_SIZE)
);
PageTable::with_fast_page((m_module.start + m_offset) & PAGE_ADDR_MASK, [&] {
memcpy(m_data_buffer + m_data_size, PageTable::fast_page_as_ptr(m_offset % PAGE_SIZE), to_copy);
});
m_data_size += to_copy;
m_offset += to_copy;
}
return true;
}
uint64_t bytes_consumed() const override
{
return bytes_produced();
}
private:
const BootModule& m_module;
size_t m_offset { 0 };
};
class DataSourceGZip final : public DataSource
{
public:
DataSourceGZip(BAN::UniqPtr<DataSource>&& data_source)
: m_data_source(BAN::move(data_source))
, m_decompressor(LibDEFLATE::StreamType::GZip)
{ }
BAN::ErrorOr<bool> produce_data() override
{
if (m_is_done)
return false;
bool did_produce_data { false };
for (;;)
{
TRY(m_data_source->produce_data());
size_t input_consumed, output_produced;
const auto status = TRY(m_decompressor.decompress(
m_data_source->data(),
input_consumed,
{ m_data_buffer + m_data_size, sizeof(m_data_buffer) - m_data_size },
output_produced
));
m_data_source->pop_data(input_consumed);
m_data_size += output_produced;
if (output_produced)
did_produce_data = true;
switch (status)
{
using DecompStatus = LibDEFLATE::Decompressor::Status;
case DecompStatus::Done:
m_is_done = true;
return did_produce_data;
case DecompStatus::NeedMoreInput:
break;
case DecompStatus::NeedMoreOutput:
return did_produce_data;
}
}
}
uint64_t bytes_consumed() const override
{
return m_data_source->bytes_consumed();
}
private:
BAN::UniqPtr<DataSource> m_data_source;
LibDEFLATE::Decompressor m_decompressor;
bool m_is_done { false };
};
static BAN::ErrorOr<void> unpack_boot_module_into_directory(BAN::RefPtr<Inode> root_inode, DataSource& data_source);
BAN::ErrorOr<bool> unpack_boot_module_into_directory(BAN::RefPtr<Inode> root_inode, const BootModule& module)
{
ASSERT(root_inode->mode().ifdir());
BAN::UniqPtr<DataSource> data_source = TRY(BAN::UniqPtr<DataSourceRaw>::create(module));
bool is_compressed = false;
TRY(data_source->produce_data());
if (data_source->data_size() >= 2 && memcmp(&data_source->data()[0], "\x1F\x8B", 2) == 0)
{
data_source = TRY(BAN::UniqPtr<DataSourceGZip>::create(BAN::move(data_source)));
is_compressed = true;
}
TRY(data_source->produce_data());
if (data_source->data_size() < 512 || memcmp(&data_source->data()[257], "ustar", 5) != 0)
{
dwarnln("Unrecognized initrd format");
return false; return false;
} }
const auto module_size_kib = module.size / 1024; if (module.size < 512)
dprintln("unpacking {}.{3} MiB{} initrd", return false;
module_size_kib / 1024, (module_size_kib % 1024) * 1000 / 1024,
is_compressed ? " compressed" : ""
);
const auto unpack_ms1 = SystemTimer::get().ms_since_boot(); bool has_ustar_signature;
TRY(unpack_boot_module_into_directory(root_inode, *data_source)); PageTable::with_fast_page(module.start, [&] {
const auto unpack_ms2 = SystemTimer::get().ms_since_boot(); has_ustar_signature = memcmp(PageTable::fast_page_as_ptr(257), "ustar", 5) == 0;
});
const auto duration_ms = unpack_ms2 - unpack_ms1; return has_ustar_signature;
dprintln("unpacking {}.{3} MiB{} initrd took {}.{3} s",
module_size_kib / 1024, (module_size_kib % 1024) * 1000 / 1024,
is_compressed ? " compressed" : "",
duration_ms / 1000, duration_ms % 1000
);
if (is_compressed)
{
const auto uncompressed_kib = data_source->bytes_produced() / 1024;
dprintln("uncompressed size {}.{3} MiB",
uncompressed_kib / 1024, (uncompressed_kib % 1024) * 1000 / 1024
);
}
return true;
} }
BAN::ErrorOr<void> unpack_boot_module_into_directory(BAN::RefPtr<Inode> root_inode, DataSource& data_source) BAN::ErrorOr<void> unpack_boot_module_into_filesystem(BAN::RefPtr<FileSystem> filesystem, const BootModule& module)
{ {
ASSERT(is_ustar_boot_module(module));
auto root_inode = filesystem->root_inode();
uint8_t* temp_page = static_cast<uint8_t*>(kmalloc(PAGE_SIZE));
if (temp_page == nullptr)
return BAN::Error::from_errno(ENOMEM);
BAN::ScopeGuard _([temp_page] { kfree(temp_page); });
BAN::String next_file_name; BAN::String next_file_name;
BAN::String next_link_name; BAN::String next_link_name;
constexpr uint32_t print_interval_ms = 1000; size_t offset = 0;
auto next_print_ms = SystemTimer::get().ms_since_boot() + print_interval_ms; while (offset + 512 <= module.size)
while (TRY(data_source.produce_data()), data_source.data_size() >= 512)
{ {
if (SystemTimer::get().ms_since_boot() >= next_print_ms) size_t file_size = 0;
{ mode_t file_mode = 0;
const auto kib_consumed = data_source.bytes_consumed() / 1024; uid_t file_uid = 0;
const auto kib_produced = data_source.bytes_produced() / 1024; gid_t file_gid = 0;
if (kib_consumed == kib_produced) uint8_t file_type = 0;
{ char file_path[100 + 1 + 155 + 1] {};
dprintln(" ... {}.{3} MiB",
kib_consumed / 1024, (kib_consumed % 1024) * 1000 / 1024
);
}
else
{
dprintln(" ... {}.{3} MiB ({}.{3} MiB)",
kib_consumed / 1024, (kib_consumed % 1024) * 1000 / 1024,
kib_produced / 1024, (kib_produced % 1024) * 1000 / 1024
);
}
next_print_ms = SystemTimer::get().ms_since_boot() + print_interval_ms;
}
const auto parse_octal = PageTable::with_fast_page((module.start + offset) & PAGE_ADDR_MASK, [&] {
[&data_source](size_t offset, size_t length) -> size_t const size_t page_off = offset % PAGE_SIZE;
{
size_t result = 0; const auto parse_octal =
for (size_t i = 0; i < length; i++) [page_off](size_t offset, size_t length) -> size_t
{ {
const char ch = data_source.data()[offset + i]; size_t result = 0;
if (ch == '\0') for (size_t i = 0; i < length; i++)
break; {
result = (result * 8) + (ch - '0'); const char ch = PageTable::fast_page_as<char>(page_off + offset + i);
} if (ch == '\0')
return result; break;
}; result = (result * 8) + (ch - '0');
}
return result;
};
if (memcmp(&data_source.data()[257], "ustar", 5) != 0) if (memcmp(PageTable::fast_page_as_ptr(page_off + 257), "ustar", 5)) {
file_size = SIZE_MAX;
return;
}
memcpy(file_path, PageTable::fast_page_as_ptr(page_off + 345), 155);
const size_t prefix_len = strlen(file_path);
file_path[prefix_len] = '/';
memcpy(file_path + prefix_len + 1, PageTable::fast_page_as_ptr(page_off), 100);
file_mode = parse_octal(100, 8);
file_uid = parse_octal(108, 8);
file_gid = parse_octal(116, 8);
file_size = parse_octal(124, 12);
file_type = PageTable::fast_page_as<char>(page_off + 156);
});
if (file_size == SIZE_MAX)
break;
if (offset + 512 + file_size > module.size)
break; break;
char file_path[100 + 1 + 155 + 1]; auto parent_inode = filesystem->root_inode();
memcpy(file_path, &data_source.data()[345], 155);
const size_t prefix_len = strlen(file_path);
file_path[prefix_len] = '/';
memcpy(file_path + prefix_len + 1, &data_source.data()[0], 100);
mode_t file_mode = parse_octal(100, 8);
const uid_t file_uid = parse_octal(108, 8);
const gid_t file_gid = parse_octal(116, 8);
const size_t file_size = parse_octal(124, 12);
const uint8_t file_type = data_source.data()[156];
auto parent_inode = root_inode;
auto file_path_parts = TRY(BAN::StringView(next_file_name.empty() ? file_path : next_file_name.sv()).split('/')); auto file_path_parts = TRY(BAN::StringView(next_file_name.empty() ? file_path : next_file_name.sv()).split('/'));
for (size_t i = 0; i < file_path_parts.size() - 1; i++) for (size_t i = 0; i < file_path_parts.size() - 1; i++)
@@ -279,33 +111,27 @@ namespace Kernel
auto file_name_sv = file_path_parts.back(); auto file_name_sv = file_path_parts.back();
bool did_consume_data = false;
if (file_type == 'L' || file_type == 'K') if (file_type == 'L' || file_type == 'K')
{ {
auto& target_str = (file_type == 'L') ? next_file_name : next_link_name; auto& target = (file_type == 'L') ? next_file_name : next_link_name;
TRY(target_str.resize(file_size)); TRY(target.resize(file_size));
data_source.pop_data(512);
size_t nwritten = 0; size_t nwritten = 0;
while (nwritten < file_size) while (nwritten < file_size)
{ {
TRY(data_source.produce_data()); const paddr_t paddr = module.start + offset + 512 + nwritten;
if (data_source.data_size() == 0) PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
return {}; memcpy(temp_page, PageTable::fast_page_as_ptr(), PAGE_SIZE);
});
const size_t to_copy = BAN::Math::min(data_source.data_size(), file_size - nwritten); const size_t page_off = paddr % PAGE_SIZE;
memcpy(target_str.data() + nwritten, data_source.data().data(), to_copy); const size_t to_write = BAN::Math::min(file_size - nwritten, PAGE_SIZE - page_off);
nwritten += to_copy; memcpy(target.data() + nwritten, temp_page + page_off, to_write);
nwritten += to_write;
data_source.pop_data(to_copy);
} }
did_consume_data = true; while (!target.empty() && target.back() == '\0')
target.pop_back();
while (!target_str.empty() && target_str.back() == '\0')
target_str.pop_back();
} }
else if (file_type == DIRTYPE) else if (file_type == DIRTYPE)
{ {
@@ -323,11 +149,14 @@ namespace Kernel
link_name = next_link_name.sv(); link_name = next_link_name.sv();
else else
{ {
memcpy(link_buffer, &data_source.data()[157], 100); const paddr_t paddr = module.start + offset;
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
memcpy(link_buffer, PageTable::fast_page_as_ptr((paddr % PAGE_SIZE) + 157), 100);
});
link_name = link_buffer; link_name = link_buffer;
} }
auto target_inode = root_inode; auto target_inode = filesystem->root_inode();
auto link_path_parts = TRY(link_name.split('/')); auto link_path_parts = TRY(link_name.split('/'));
for (const auto part : link_path_parts) for (const auto part : link_path_parts)
@@ -359,7 +188,10 @@ namespace Kernel
link_name = next_link_name.sv(); link_name = next_link_name.sv();
else else
{ {
memcpy(link_buffer, &data_source.data()[157], 100); const paddr_t paddr = module.start + offset;
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
memcpy(link_buffer, PageTable::fast_page_as_ptr((paddr % PAGE_SIZE) + 157), 100);
});
link_name = link_buffer; link_name = link_buffer;
} }
@@ -371,26 +203,26 @@ namespace Kernel
{ {
if (auto ret = parent_inode->create_file(file_name_sv, file_mode, file_uid, file_gid); ret.is_error()) if (auto ret = parent_inode->create_file(file_name_sv, file_mode, file_uid, file_gid); ret.is_error())
dwarnln("failed to create file '{}': {}", file_name_sv, ret.error()); dwarnln("failed to create file '{}': {}", file_name_sv, ret.error());
else if (file_size) else
{ {
auto inode = TRY(parent_inode->find_inode(file_name_sv)); if (file_size)
data_source.pop_data(512);
size_t nwritten = 0;
while (nwritten < file_size)
{ {
TRY(data_source.produce_data()); auto inode = TRY(parent_inode->find_inode(file_name_sv));
ASSERT(data_source.data_size() > 0); // what to do?
const size_t to_write = BAN::Math::min(file_size - nwritten, data_source.data_size()); size_t nwritten = 0;
TRY(inode->write(nwritten, data_source.data().slice(0, to_write))); while (nwritten < file_size)
nwritten += to_write; {
const paddr_t paddr = module.start + offset + 512 + nwritten;
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
memcpy(temp_page, PageTable::fast_page_as_ptr(), PAGE_SIZE);
});
data_source.pop_data(to_write); const size_t page_off = paddr % PAGE_SIZE;
const size_t to_write = BAN::Math::min(file_size - nwritten, PAGE_SIZE - page_off);
TRY(inode->write(nwritten, { temp_page + page_off, to_write }));
nwritten += to_write;
}
} }
did_consume_data = true;
} }
} }
@@ -400,27 +232,9 @@ namespace Kernel
next_link_name.clear(); next_link_name.clear();
} }
if (!did_consume_data) offset += 512 + file_size;
{ if (auto rem = offset % 512)
data_source.pop_data(512); offset += 512 - rem;
size_t consumed = 0;
while (consumed < file_size)
{
TRY(data_source.produce_data());
if (data_source.data_size() == 0)
return {};
data_source.pop_data(BAN::Math::min(file_size - consumed, data_source.data_size()));
}
}
if (const auto rem = file_size % 512)
{
TRY(data_source.produce_data());
if (data_source.data_size() < rem)
return {};
data_source.pop_data(512 - rem);
}
} }
return {}; return {};

View File

@@ -61,22 +61,18 @@ namespace Kernel
if (filesystem_or_error.is_error()) if (filesystem_or_error.is_error())
panic("Failed to create fallback filesystem: {}", filesystem_or_error.error()); panic("Failed to create fallback filesystem: {}", filesystem_or_error.error());
dprintln("Trying to load fallback filesystem from {} modules", g_boot_info.modules.size()); dprintln("Loading fallback filesystem from {} modules", g_boot_info.modules.size());
auto filesystem = BAN::RefPtr<FileSystem>::adopt(filesystem_or_error.release_value()); auto filesystem = BAN::RefPtr<FileSystem>::adopt(filesystem_or_error.release_value());
bool loaded_initrd = false;
for (const auto& module : g_boot_info.modules) for (const auto& module : g_boot_info.modules)
{ {
if (auto ret = unpack_boot_module_into_directory(filesystem->root_inode(), module); ret.is_error()) if (!is_ustar_boot_module(module))
continue;
if (auto ret = unpack_boot_module_into_filesystem(filesystem, module); ret.is_error())
dwarnln("Failed to unpack boot module: {}", ret.error()); dwarnln("Failed to unpack boot module: {}", ret.error());
else
loaded_initrd |= ret.value();
} }
if (!loaded_initrd)
panic("Could not load initrd from any boot module :(");
return filesystem; return filesystem;
} }

View File

@@ -164,33 +164,6 @@ namespace Kernel
"Unkown Exception 0x1F", "Unkown Exception 0x1F",
}; };
extern "C" uint8_t safe_user_memcpy[];
extern "C" uint8_t safe_user_memcpy_end[];
extern "C" uint8_t safe_user_memcpy_fault[];
extern "C" uint8_t safe_user_strncpy[];
extern "C" uint8_t safe_user_strncpy_end[];
extern "C" uint8_t safe_user_strncpy_fault[];
struct safe_user_page_fault
{
const uint8_t* ip_start;
const uint8_t* ip_end;
const uint8_t* ip_fault;
};
static constexpr safe_user_page_fault s_safe_user_page_faults[] {
{
.ip_start = safe_user_memcpy,
.ip_end = safe_user_memcpy_end,
.ip_fault = safe_user_memcpy_fault,
},
{
.ip_start = safe_user_strncpy,
.ip_end = safe_user_strncpy_end,
.ip_fault = safe_user_strncpy_fault,
},
};
extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack* interrupt_stack, const Registers* regs) extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack* interrupt_stack, const Registers* regs)
{ {
if (g_paniced) if (g_paniced)
@@ -204,62 +177,34 @@ namespace Kernel
const pid_t tid = Thread::current_tid(); const pid_t tid = Thread::current_tid();
const pid_t pid = (tid && Thread::current().has_process()) ? Process::current().pid() : 0; const pid_t pid = (tid && Thread::current().has_process()) ? Process::current().pid() : 0;
switch (isr) const char* process_name = "";
if (tid)
{ {
case ISR::PageFault: auto& thread = Thread::current();
thread.save_sse();
if (isr == ISR::PageFault && Thread::current().is_userspace())
{ {
if (pid == 0 || !Thread::current().is_userspace()) if (pid)
break;
PageFaultError page_fault_error;
page_fault_error.raw = error;
Processor::set_interrupt_state(InterruptState::Enabled);
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2, page_fault_error.write, page_fault_error.instruction);
Processor::set_interrupt_state(InterruptState::Disabled);
if (result.is_error())
{ {
dwarnln("Demand paging: {}", result.error()); PageFaultError page_fault_error;
page_fault_error.raw = error;
// TODO: this is too strict, we should maybe do SIGBUS and
// SIGKILL only on recursive exceptions
Processor::set_interrupt_state(InterruptState::Enabled); Processor::set_interrupt_state(InterruptState::Enabled);
Thread::current().handle_signal(SIGKILL, {}); auto result = Process::current().allocate_page_for_demand_paging(regs->cr2, page_fault_error.write, page_fault_error.instruction);
Processor::set_interrupt_state(InterruptState::Disabled); Processor::set_interrupt_state(InterruptState::Disabled);
return; if (!result.is_error() && result.value())
goto done;
if (result.is_error())
{
dwarnln("Demand paging: {}", result.error());
Thread::current().handle_signal(SIGKILL, {});
goto done;
}
} }
if (result.value())
return;
const uint8_t* ip = reinterpret_cast<const uint8_t*>(interrupt_stack->ip);
for (const auto& safe_user : s_safe_user_page_faults)
{
if (ip < safe_user.ip_start || ip >= safe_user.ip_end)
continue;
interrupt_stack->ip = reinterpret_cast<vaddr_t>(safe_user.ip_fault);
return;
}
break;
}
case ISR::DeviceNotAvailable:
{
if (pid == 0 || !Thread::current().is_userspace())
break;
Processor::enable_sse();
if (auto* sse_thread = Processor::get_current_sse_thread())
sse_thread->save_sse();
auto* current_thread = &Thread::current();
current_thread->load_sse();
Processor::set_current_sse_thread(current_thread);
return;
} }
} }
@@ -280,9 +225,8 @@ namespace Kernel
); );
} }
const char* process_name = (tid && Thread::current().has_process()) if (Thread::current().has_process())
? Process::current().name() process_name = Process::current().name();
: nullptr;
#if ARCH(x86_64) #if ARCH(x86_64)
dwarnln( dwarnln(
@@ -319,15 +263,11 @@ namespace Kernel
#endif #endif
if (isr == ISR::PageFault) if (isr == ISR::PageFault)
PageTable::current().debug_dump(); PageTable::current().debug_dump();
#if ARCH(x86_64) Debug::dump_stack_trace();
Debug::dump_stack_trace(interrupt_stack->ip, regs->rbp);
#elif ARCH(i686)
Debug::dump_stack_trace(interrupt_stack->ip, regs->ebp);
#endif
Debug::s_debug_lock.unlock(InterruptState::Disabled); Debug::s_debug_lock.unlock(InterruptState::Disabled);
if (tid && GDT::is_user_segment(interrupt_stack->cs)) if (tid && Thread::current().is_userspace())
{ {
// TODO: Confirm and fix the exception to signal mappings // TODO: Confirm and fix the exception to signal mappings
@@ -358,7 +298,6 @@ namespace Kernel
case ISR::InvalidOpcode: case ISR::InvalidOpcode:
signal_info.si_signo = SIGILL; signal_info.si_signo = SIGILL;
signal_info.si_code = ILL_ILLOPC; signal_info.si_code = ILL_ILLOPC;
signal_info.si_addr = reinterpret_cast<void*>(interrupt_stack->ip);
break; break;
case ISR::PageFault: case ISR::PageFault:
signal_info.si_signo = SIGSEGV; signal_info.si_signo = SIGSEGV;
@@ -366,7 +305,6 @@ namespace Kernel
signal_info.si_code = SEGV_ACCERR; signal_info.si_code = SEGV_ACCERR;
else else
signal_info.si_code = SEGV_MAPERR; signal_info.si_code = SEGV_MAPERR;
signal_info.si_addr = reinterpret_cast<void*>(regs->cr2);
break; break;
default: default:
dwarnln("Unhandled exception"); dwarnln("Unhandled exception");
@@ -374,9 +312,7 @@ namespace Kernel
break; break;
} }
Processor::set_interrupt_state(InterruptState::Enabled);
Thread::current().handle_signal(signal_info.si_signo, signal_info); Thread::current().handle_signal(signal_info.si_signo, signal_info);
Processor::set_interrupt_state(InterruptState::Disabled);
} }
else else
{ {
@@ -384,6 +320,17 @@ namespace Kernel
} }
ASSERT(Thread::current().state() != Thread::State::Terminated); ASSERT(Thread::current().state() != Thread::State::Terminated);
done:
Thread::current().load_sse();
}
extern "C" void cpp_yield_handler(InterruptStack* interrupt_stack, InterruptRegisters* interrupt_registers)
{
// yield is raised through kernel software interrupt
ASSERT(!InterruptController::get().is_in_service(IRQ_YIELD - IRQ_VECTOR_BASE));
ASSERT(!GDT::is_user_segment(interrupt_stack->cs));
Processor::scheduler().reschedule(interrupt_stack, interrupt_registers);
} }
extern "C" void cpp_ipi_handler() extern "C" void cpp_ipi_handler()
@@ -404,6 +351,8 @@ namespace Kernel
asm volatile("cli; 1: hlt; jmp 1b"); asm volatile("cli; 1: hlt; jmp 1b");
} }
Thread::current().save_sse();
ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE)); ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE));
InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE); InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE);
@@ -411,6 +360,12 @@ namespace Kernel
Process::update_alarm_queue(); Process::update_alarm_queue();
Processor::scheduler().timer_interrupt(); Processor::scheduler().timer_interrupt();
auto& current_thread = Thread::current();
if (current_thread.can_add_signal_to_execute())
current_thread.handle_signal();
Thread::current().load_sse();
} }
extern "C" void cpp_irq_handler(uint32_t irq) extern "C" void cpp_irq_handler(uint32_t irq)
@@ -428,22 +383,23 @@ namespace Kernel
if (!InterruptController::get().is_in_service(irq)) if (!InterruptController::get().is_in_service(irq))
return; return;
Thread::current().save_sse();
InterruptController::get().eoi(irq); InterruptController::get().eoi(irq);
if (auto* handler = s_interruptables[irq]) if (auto* handler = s_interruptables[irq])
handler->handle_irq(); handler->handle_irq();
else else
dprintln("no handler for irq 0x{2H}", irq); dprintln("no handler for irq 0x{2H}", irq);
auto& current_thread = Thread::current();
if (current_thread.can_add_signal_to_execute())
current_thread.handle_signal();
Processor::scheduler().reschedule_if_idle(); Processor::scheduler().reschedule_if_idle();
ASSERT(Thread::current().state() != Thread::State::Terminated); ASSERT(Thread::current().state() != Thread::State::Terminated);
}
extern "C" void cpp_check_signal() Thread::current().load_sse();
{
Processor::set_interrupt_state(InterruptState::Enabled);
Thread::current().handle_signal_if_interrupted();
Processor::set_interrupt_state(InterruptState::Disabled);
} }
void IDT::register_interrupt_handler(uint8_t index, void (*handler)(), uint8_t ist) void IDT::register_interrupt_handler(uint8_t index, void (*handler)(), uint8_t ist)
@@ -485,6 +441,7 @@ namespace Kernel
IRQ_LIST_X IRQ_LIST_X
#undef X #undef X
extern "C" void asm_yield_handler();
extern "C" void asm_ipi_handler(); extern "C" void asm_ipi_handler();
extern "C" void asm_timer_handler(); extern "C" void asm_timer_handler();
#if ARCH(i686) #if ARCH(i686)
@@ -520,6 +477,7 @@ namespace Kernel
static_assert(DoubleFault == 8); static_assert(DoubleFault == 8);
#endif #endif
idt->register_interrupt_handler(IRQ_YIELD, asm_yield_handler);
idt->register_interrupt_handler(IRQ_IPI, asm_ipi_handler); idt->register_interrupt_handler(IRQ_IPI, asm_ipi_handler);
idt->register_interrupt_handler(IRQ_TIMER, asm_timer_handler); idt->register_interrupt_handler(IRQ_TIMER, asm_timer_handler);
#if ARCH(i686) #if ARCH(i686)

View File

@@ -136,9 +136,6 @@ namespace Kernel::Input
m_scancode_to_keycode_extended[0x49] = keycode_function(18); m_scancode_to_keycode_extended[0x49] = keycode_function(18);
m_scancode_to_keycode_extended[0x51] = keycode_function(19); m_scancode_to_keycode_extended[0x51] = keycode_function(19);
m_scancode_to_keycode_normal[0x46] = keycode_function(20); m_scancode_to_keycode_normal[0x46] = keycode_function(20);
m_scancode_to_keycode_extended[0x20] = keycode_function(21);
m_scancode_to_keycode_extended[0x2E] = keycode_function(22);
m_scancode_to_keycode_extended[0x30] = keycode_function(23);
// Arrow keys // Arrow keys
m_scancode_to_keycode_extended[0x48] = keycode_normal(5, 0); m_scancode_to_keycode_extended[0x48] = keycode_normal(5, 0);
@@ -249,9 +246,6 @@ namespace Kernel::Input
m_scancode_to_keycode_extended[0x7D] = keycode_function(18); m_scancode_to_keycode_extended[0x7D] = keycode_function(18);
m_scancode_to_keycode_extended[0x7A] = keycode_function(19); m_scancode_to_keycode_extended[0x7A] = keycode_function(19);
m_scancode_to_keycode_normal[0x7E] = keycode_function(20); m_scancode_to_keycode_normal[0x7E] = keycode_function(20);
m_scancode_to_keycode_extended[0x23] = keycode_function(21);
m_scancode_to_keycode_extended[0x21] = keycode_function(22);
m_scancode_to_keycode_extended[0x32] = keycode_function(23);
// Arrow keys // Arrow keys
m_scancode_to_keycode_extended[0x75] = keycode_normal(5, 0); m_scancode_to_keycode_extended[0x75] = keycode_normal(5, 0);
@@ -362,9 +356,6 @@ namespace Kernel::Input
m_scancode_to_keycode_normal[0x6F] = keycode_function(18); m_scancode_to_keycode_normal[0x6F] = keycode_function(18);
m_scancode_to_keycode_normal[0x6D] = keycode_function(19); m_scancode_to_keycode_normal[0x6D] = keycode_function(19);
m_scancode_to_keycode_normal[0x5F] = keycode_function(20); m_scancode_to_keycode_normal[0x5F] = keycode_function(20);
m_scancode_to_keycode_normal[0x9C] = keycode_function(21);
m_scancode_to_keycode_normal[0x9D] = keycode_function(22);
m_scancode_to_keycode_normal[0x95] = keycode_function(23);
// Arrow keys // Arrow keys
m_scancode_to_keycode_normal[0x63] = keycode_normal(5, 0); m_scancode_to_keycode_normal[0x63] = keycode_normal(5, 0);

View File

@@ -1,49 +0,0 @@
#include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/PageTable.h>
namespace Kernel
{
BAN::ErrorOr<BAN::UniqPtr<ByteRingBuffer>> ByteRingBuffer::create(size_t size)
{
ASSERT(size % PAGE_SIZE == 0);
const size_t page_count = size / PAGE_SIZE;
auto* buffer_ptr = new ByteRingBuffer(size);
if (buffer_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto buffer = BAN::UniqPtr<ByteRingBuffer>::adopt(buffer_ptr);
buffer->m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(page_count * 2, KERNEL_OFFSET);
if (buffer->m_vaddr == 0)
return BAN::Error::from_errno(ENOMEM);
for (size_t i = 0; i < page_count; i++)
{
const paddr_t paddr = Heap::get().take_free_page();
if (paddr == 0)
return BAN::Error::from_errno(ENOMEM);
PageTable::kernel().map_page_at(paddr, buffer->m_vaddr + i * PAGE_SIZE, PageTable::ReadWrite | PageTable::Present);
PageTable::kernel().map_page_at(paddr, buffer->m_vaddr + size + i * PAGE_SIZE, PageTable::ReadWrite | PageTable::Present);
}
return buffer;
}
ByteRingBuffer::~ByteRingBuffer()
{
if (m_vaddr == 0)
return;
for (size_t i = 0; i < m_capacity / PAGE_SIZE; i++)
{
const paddr_t paddr = PageTable::kernel().physical_address_of(m_vaddr + i * PAGE_SIZE);
if (paddr == 0)
break;
Heap::get().release_page(paddr);
}
PageTable::kernel().unmap_range(m_vaddr, m_capacity * 2);
}
}

View File

@@ -2,62 +2,11 @@
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <BAN/Sort.h>
extern uint8_t g_kernel_end[]; extern uint8_t g_kernel_end[];
namespace Kernel namespace Kernel
{ {
struct ReservedRegion
{
paddr_t paddr;
uint64_t size;
};
static BAN::Vector<ReservedRegion> get_reserved_regions()
{
BAN::Vector<ReservedRegion> reserved_regions;
MUST(reserved_regions.reserve(2 + g_boot_info.modules.size()));
MUST(reserved_regions.emplace_back(0, 0x100000));
MUST(reserved_regions.emplace_back(g_boot_info.kernel_paddr, reinterpret_cast<size_t>(g_kernel_end - KERNEL_OFFSET)));
for (const auto& module : g_boot_info.modules)
MUST(reserved_regions.emplace_back(module.start, module.size));
// page align regions
for (auto& region : reserved_regions)
{
const auto rem = region.paddr % PAGE_SIZE;
region.paddr -= rem;
region.size += rem;
if (const auto rem = region.size % PAGE_SIZE)
region.size += PAGE_SIZE - rem;
}
// sort regions
BAN::sort::sort(reserved_regions.begin(), reserved_regions.end(),
[](const auto& lhs, const auto& rhs) -> bool {
if (lhs.paddr == rhs.paddr)
return lhs.size < rhs.size;
return lhs.paddr < rhs.paddr;
}
);
// combine overlapping regions
for (size_t i = 1; i < reserved_regions.size(); i++)
{
auto& prev = reserved_regions[i - 1];
auto& curr = reserved_regions[i - 0];
if (prev.paddr > curr.paddr + curr.size || curr.paddr > prev.paddr + prev.size)
continue;
prev.size = BAN::Math::max(prev.size, curr.paddr + curr.size - prev.paddr);
reserved_regions.remove(i--);
}
return reserved_regions;
}
static Heap* s_instance = nullptr; static Heap* s_instance = nullptr;
void Heap::initialize() void Heap::initialize()
@@ -79,7 +28,6 @@ namespace Kernel
if (g_boot_info.memory_map_entries.empty()) if (g_boot_info.memory_map_entries.empty())
panic("Bootloader did not provide a memory map"); panic("Bootloader did not provide a memory map");
auto reserved_regions = get_reserved_regions();
for (const auto& entry : g_boot_info.memory_map_entries) for (const auto& entry : g_boot_info.memory_map_entries)
{ {
const char* entry_type_string = nullptr; const char* entry_type_string = nullptr;
@@ -110,71 +58,33 @@ namespace Kernel
if (entry.type != MemoryMapEntry::Type::Available) if (entry.type != MemoryMapEntry::Type::Available)
continue; continue;
paddr_t e_start = entry.address; // FIXME: only reserve kernel area and modules, not everything from 0 -> kernel end
if (auto rem = e_start % PAGE_SIZE) paddr_t start = entry.address;
e_start = PAGE_SIZE - rem; if (start < (vaddr_t)g_kernel_end - KERNEL_OFFSET + g_boot_info.kernel_paddr)
start = (vaddr_t)g_kernel_end - KERNEL_OFFSET + g_boot_info.kernel_paddr;
paddr_t e_end = entry.address + entry.length; for (const auto& module : g_boot_info.modules)
if (auto rem = e_end % PAGE_SIZE) if (start < module.start + module.size)
e_end -= rem; start = module.start + module.size;
for (const auto& reserved_region : reserved_regions)
{
const paddr_t r_start = reserved_region.paddr;
const paddr_t r_end = reserved_region.paddr + reserved_region.size;
if (r_end < e_start)
continue;
if (r_start > e_end)
break;
const paddr_t end = BAN::Math::max(e_start, r_start);
if (e_start + 2 * PAGE_SIZE <= end)
MUST(m_physical_ranges.emplace_back(e_start, end - e_start));
e_start = BAN::Math::max(e_start, BAN::Math::min(e_end, r_end));
}
if (e_start + 2 * PAGE_SIZE <= e_end)
MUST(m_physical_ranges.emplace_back(e_start, e_end - e_start));
}
uint64_t total_kibi_bytes = 0;
for (auto& range : m_physical_ranges)
{
const uint64_t kibi_bytes = range.usable_memory() / 1024;
dprintln("RAM {8H}->{8H} ({}.{3} MiB)", range.start(), range.end(), kibi_bytes / 1024, kibi_bytes % 1024);
total_kibi_bytes += kibi_bytes;
}
dprintln("Total RAM {}.{3} MiB", total_kibi_bytes / 1024, total_kibi_bytes % 1024);
}
void Heap::release_boot_modules()
{
const auto modules = BAN::move(g_boot_info.modules);
uint64_t kibi_bytes = 0;
for (const auto& module : modules)
{
vaddr_t start = module.start;
if (auto rem = start % PAGE_SIZE) if (auto rem = start % PAGE_SIZE)
start += PAGE_SIZE - rem; start += PAGE_SIZE - rem;
vaddr_t end = module.start + module.size; paddr_t end = entry.address + entry.length;
if (auto rem = end % PAGE_SIZE) if (auto rem = end % PAGE_SIZE)
end -= rem; end -= rem;
const size_t size = end - start; // Physical pages needs atleast 2 pages
if (size < 2 * PAGE_SIZE) if (end > start + PAGE_SIZE)
continue; MUST(m_physical_ranges.emplace_back(start, end - start));
SpinLockGuard _(m_lock);
MUST(m_physical_ranges.emplace_back(start, size));
kibi_bytes += m_physical_ranges.back().usable_memory() / 1024;
} }
if (kibi_bytes) size_t total = 0;
dprintln("Released {}.{3} MiB of RAM from boot modules", kibi_bytes / 1024, kibi_bytes % 1024); for (auto& range : m_physical_ranges)
{
size_t bytes = range.usable_memory();
dprintln("RAM {8H}->{8H} ({}.{} MB)", range.start(), range.end(), bytes / (1 << 20), bytes % (1 << 20) * 1000 / (1 << 20));
total += bytes;
}
dprintln("Total RAM {}.{} MB", total / (1 << 20), total % (1 << 20) * 1000 / (1 << 20));
} }
paddr_t Heap::take_free_page() paddr_t Heap::take_free_page()

View File

@@ -1,6 +1,5 @@
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/MemoryBackedRegion.h> #include <kernel/Memory/MemoryBackedRegion.h>
#include <kernel/Lock/LockGuard.h>
namespace Kernel namespace Kernel
{ {
@@ -15,9 +14,6 @@ namespace Kernel
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto region = BAN::UniqPtr<MemoryBackedRegion>::adopt(region_ptr); auto region = BAN::UniqPtr<MemoryBackedRegion>::adopt(region_ptr);
const size_t page_count = (size + PAGE_SIZE - 1) / PAGE_SIZE;
TRY(region->m_physical_pages.resize(page_count, nullptr));
TRY(region->initialize(address_range)); TRY(region->initialize(address_range));
return region; return region;
@@ -32,75 +28,38 @@ namespace Kernel
{ {
ASSERT(m_type == Type::PRIVATE); ASSERT(m_type == Type::PRIVATE);
for (auto* page : m_physical_pages) size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
if (page && --page->ref_count == 0) for (size_t i = 0; i < needed_pages; i++)
delete page; {
} paddr_t paddr = m_page_table.physical_address_of(m_vaddr + i * PAGE_SIZE);
if (paddr != 0)
MemoryBackedRegion::PhysicalPage::~PhysicalPage() Heap::get().release_page(paddr);
{ }
Heap::get().release_page(paddr);
} }
BAN::ErrorOr<bool> MemoryBackedRegion::allocate_page_containing_impl(vaddr_t address, bool wants_write) BAN::ErrorOr<bool> MemoryBackedRegion::allocate_page_containing_impl(vaddr_t address, bool wants_write)
{ {
ASSERT(m_type == Type::PRIVATE); ASSERT(m_type == Type::PRIVATE);
ASSERT(contains(address)); ASSERT(contains(address));
(void)wants_write;
const vaddr_t vaddr = address & PAGE_ADDR_MASK; // Check if address is already mapped
vaddr_t vaddr = address & PAGE_ADDR_MASK;
if (m_page_table.physical_address_of(vaddr) != 0)
return false;
LockGuard _(m_mutex); // Map new physcial page to address
paddr_t paddr = Heap::get().take_free_page();
auto& physical_page = m_physical_pages[(vaddr - m_vaddr) / PAGE_SIZE];
if (physical_page == nullptr)
{
const paddr_t paddr = Heap::get().take_free_page();
if (paddr == 0)
return BAN::Error::from_errno(ENOMEM);
physical_page = new PhysicalPage(paddr);
if (physical_page == nullptr)
return BAN::Error::from_errno(ENOMEM);
m_page_table.map_page_at(paddr, vaddr, m_flags);
PageTable::with_fast_page(paddr, [] {
memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE);
});
return true;
}
if (auto is_only_ref = (physical_page->ref_count == 1); is_only_ref || !wants_write)
{
auto flags = m_flags;
if (!is_only_ref)
flags &= ~PageTable::ReadWrite;
m_page_table.map_page_at(physical_page->paddr, vaddr, flags);
return true;
}
const paddr_t paddr = Heap::get().take_free_page();
if (paddr == 0) if (paddr == 0)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto* new_physical_page = new PhysicalPage(paddr);
if (new_physical_page == nullptr)
return BAN::Error::from_errno(ENOMEM);
m_page_table.map_page_at(paddr, vaddr, m_flags); m_page_table.map_page_at(paddr, vaddr, m_flags);
ASSERT(&m_page_table == &PageTable::current()); // Zero out the new page
PageTable::with_fast_page(physical_page->paddr, [vaddr] { PageTable::with_fast_page(paddr, [&] {
memcpy(reinterpret_cast<void*>(vaddr), PageTable::fast_page_as_ptr(), PAGE_SIZE); memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE);
}); });
if (--physical_page->ref_count == 0)
delete physical_page;
physical_page = new_physical_page;
return true; return true;
} }
@@ -108,20 +67,16 @@ namespace Kernel
{ {
ASSERT(&PageTable::current() == &m_page_table); ASSERT(&PageTable::current() == &m_page_table);
LockGuard _(m_mutex);
const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK; const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
auto result = TRY(MemoryBackedRegion::create(new_page_table, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags, m_status_flags)); auto result = TRY(MemoryBackedRegion::create(new_page_table, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags, m_status_flags));
if (writable()) for (size_t offset = 0; offset < m_size; offset += PAGE_SIZE)
m_page_table.remove_writable_from_range(m_vaddr, m_size);
for (size_t i = 0; i < m_physical_pages.size(); i++)
{ {
if (m_physical_pages[i] == nullptr) paddr_t paddr = m_page_table.physical_address_of(m_vaddr + offset);
if (paddr == 0)
continue; continue;
result->m_physical_pages[i] = m_physical_pages[i]; const size_t to_copy = BAN::Math::min<size_t>(PAGE_SIZE, m_size - offset);
result->m_physical_pages[i]->ref_count++; TRY(result->copy_data_to_region(offset, (const uint8_t*)(m_vaddr + offset), to_copy));
} }
return BAN::UniqPtr<MemoryRegion>(BAN::move(result)); return BAN::UniqPtr<MemoryRegion>(BAN::move(result));
@@ -132,35 +87,20 @@ namespace Kernel
ASSERT(offset && offset < m_size); ASSERT(offset && offset < m_size);
ASSERT(offset % PAGE_SIZE == 0); ASSERT(offset % PAGE_SIZE == 0);
LockGuard _(m_mutex); auto* new_region = new MemoryBackedRegion(m_page_table, m_size - offset, m_type, m_flags, m_status_flags);
if (new_region == nullptr)
auto* new_region_ptr = new MemoryBackedRegion(m_page_table, m_size - offset, m_type, m_flags, m_status_flags);
if (new_region_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto new_region = BAN::UniqPtr<MemoryBackedRegion>::adopt(new_region_ptr);
new_region->m_vaddr = m_vaddr + offset; new_region->m_vaddr = m_vaddr + offset;
const size_t moved_pages = (m_size - offset + PAGE_SIZE - 1) / PAGE_SIZE;
TRY(new_region->m_physical_pages.resize(moved_pages));
const size_t remaining_pages = m_physical_pages.size() - moved_pages;
for (size_t i = 0; i < moved_pages; i++)
new_region->m_physical_pages[i] = m_physical_pages[remaining_pages + i];
MUST(m_physical_pages.resize(remaining_pages));
m_size = offset; m_size = offset;
return BAN::UniqPtr<MemoryRegion>(BAN::move(new_region)); return BAN::UniqPtr<MemoryRegion>::adopt(new_region);
} }
BAN::ErrorOr<void> MemoryBackedRegion::copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size) BAN::ErrorOr<void> MemoryBackedRegion::copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size)
{ {
ASSERT(offset_into_region + buffer_size <= m_size); ASSERT(offset_into_region + buffer_size <= m_size);
LockGuard _(m_mutex);
size_t written = 0; size_t written = 0;
while (written < buffer_size) while (written < buffer_size)
{ {
@@ -168,18 +108,18 @@ namespace Kernel
vaddr_t page_offset = write_vaddr % PAGE_SIZE; vaddr_t page_offset = write_vaddr % PAGE_SIZE;
size_t bytes = BAN::Math::min<size_t>(buffer_size - written, PAGE_SIZE - page_offset); size_t bytes = BAN::Math::min<size_t>(buffer_size - written, PAGE_SIZE - page_offset);
if (!(m_page_table.get_page_flags(write_vaddr & PAGE_ADDR_MASK) & PageTable::ReadWrite)) paddr_t paddr = m_page_table.physical_address_of(write_vaddr & PAGE_ADDR_MASK);
if (paddr == 0)
{ {
if (!TRY(allocate_page_containing(write_vaddr, true))) if (!TRY(allocate_page_containing(write_vaddr, false)))
{ {
dwarnln("Could not allocate page for data copying"); dwarnln("Could not allocate page for data copying");
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EFAULT);
} }
paddr = m_page_table.physical_address_of(write_vaddr & PAGE_ADDR_MASK);
ASSERT(paddr);
} }
const paddr_t paddr = m_page_table.physical_address_of(write_vaddr & PAGE_ADDR_MASK);
ASSERT(paddr);
PageTable::with_fast_page(paddr, [&] { PageTable::with_fast_page(paddr, [&] {
memcpy(PageTable::fast_page_as_ptr(page_offset), (void*)(buffer + written), bytes); memcpy(PageTable::fast_page_as_ptr(page_offset), (void*)(buffer + written), bytes);
}); });

View File

@@ -22,10 +22,8 @@ namespace Kernel
BAN::ErrorOr<void> MemoryRegion::initialize(AddressRange address_range) BAN::ErrorOr<void> MemoryRegion::initialize(AddressRange address_range)
{ {
if (auto rem = address_range.end % PAGE_SIZE) size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
address_range.end += PAGE_SIZE - rem; m_vaddr = m_page_table.reserve_free_contiguous_pages(needed_pages, address_range.start);
const size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
m_vaddr = m_page_table.reserve_free_contiguous_pages(needed_pages, address_range.start, address_range.end);
if (m_vaddr == 0) if (m_vaddr == 0)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
if (m_vaddr + m_size > address_range.end) if (m_vaddr + m_size > address_range.end)

View File

@@ -10,7 +10,7 @@ namespace Kernel
static constexpr size_t bits_per_page = PAGE_SIZE * 8; static constexpr size_t bits_per_page = PAGE_SIZE * 8;
PhysicalRange::PhysicalRange(paddr_t paddr, uint64_t size) PhysicalRange::PhysicalRange(paddr_t paddr, size_t size)
: m_paddr(paddr) : m_paddr(paddr)
, m_page_count(size / PAGE_SIZE) , m_page_count(size / PAGE_SIZE)
, m_free_pages(m_page_count) , m_free_pages(m_page_count)

View File

@@ -83,7 +83,7 @@ namespace Kernel
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> SharedMemoryObject::clone(PageTable& new_page_table) BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> SharedMemoryObject::clone(PageTable& new_page_table)
{ {
auto region = TRY(SharedMemoryObject::create(m_object, new_page_table, { .start = vaddr(), .end = vaddr() + size() })); auto region = TRY(SharedMemoryObjectManager::get().map_object(m_object->key, new_page_table, { .start = vaddr(), .end = vaddr() + size() }));
return BAN::UniqPtr<MemoryRegion>(BAN::move(region)); return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
} }

View File

@@ -110,6 +110,36 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> VirtualRange::clone(PageTable& page_table)
{
ASSERT(&PageTable::current() == &m_page_table);
ASSERT(&m_page_table != &page_table);
SpinLockGuard _(m_lock);
auto result = TRY(create_to_vaddr(page_table, vaddr(), size(), m_flags, m_preallocated, m_has_guard_pages));
const size_t page_count = size() / PAGE_SIZE;
for (size_t i = 0; i < page_count; i++)
{
if (m_paddrs[i] == 0)
continue;
if (!result->m_preallocated)
{
result->m_paddrs[i] = Heap::get().take_free_page();
if (result->m_paddrs[i] == 0)
return BAN::Error::from_errno(ENOMEM);
result->m_page_table.map_page_at(result->m_paddrs[i], vaddr() + i * PAGE_SIZE, m_flags);
}
PageTable::with_fast_page(result->m_paddrs[i], [&] {
memcpy(PageTable::fast_page_as_ptr(), reinterpret_cast<void*>(vaddr() + i * PAGE_SIZE), PAGE_SIZE);
});
}
return result;
}
BAN::ErrorOr<bool> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr) BAN::ErrorOr<bool> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr)
{ {
ASSERT(contains(vaddr)); ASSERT(contains(vaddr));
@@ -118,12 +148,12 @@ namespace Kernel
if (m_preallocated) if (m_preallocated)
return false; return false;
SpinLockGuard _(m_lock);
const size_t index = (vaddr - this->vaddr()) / PAGE_SIZE; const size_t index = (vaddr - this->vaddr()) / PAGE_SIZE;
if (m_paddrs[index]) if (m_paddrs[index])
return false; return false;
SpinLockGuard _(m_lock);
m_paddrs[index] = Heap::get().take_free_page(); m_paddrs[index] = Heap::get().take_free_page();
if (m_paddrs[index] == 0) if (m_paddrs[index] == 0)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);

View File

@@ -17,7 +17,27 @@ namespace Kernel
BAN::ErrorOr<BAN::UniqPtr<ARPTable>> ARPTable::create() BAN::ErrorOr<BAN::UniqPtr<ARPTable>> ARPTable::create()
{ {
return TRY(BAN::UniqPtr<ARPTable>::create()); auto arp_table = TRY(BAN::UniqPtr<ARPTable>::create());
arp_table->m_thread = TRY(Thread::create_kernel(
[](void* arp_table_ptr)
{
auto& arp_table = *reinterpret_cast<ARPTable*>(arp_table_ptr);
arp_table.packet_handle_task();
}, arp_table.ptr()
));
TRY(Processor::scheduler().add_thread(arp_table->m_thread));
return arp_table;
}
ARPTable::ARPTable()
{
}
ARPTable::~ARPTable()
{
if (m_thread)
m_thread->add_signal(SIGKILL, {});
m_thread = nullptr;
} }
BAN::ErrorOr<BAN::MACAddress> ARPTable::get_mac_from_ipv4(NetworkInterface& interface, BAN::IPv4Address ipv4_address) BAN::ErrorOr<BAN::MACAddress> ARPTable::get_mac_from_ipv4(NetworkInterface& interface, BAN::IPv4Address ipv4_address)
@@ -44,7 +64,7 @@ namespace Kernel
ipv4_address = interface.get_gateway(); ipv4_address = interface.get_gateway();
{ {
SpinLockGuard _(m_arp_table_lock); SpinLockGuard _(m_table_lock);
auto it = m_arp_table.find(ipv4_address); auto it = m_arp_table.find(ipv4_address);
if (it != m_arp_table.end()) if (it != m_arp_table.end())
return it->value; return it->value;
@@ -67,7 +87,7 @@ namespace Kernel
while (SystemTimer::get().ms_since_boot() < timeout) while (SystemTimer::get().ms_since_boot() < timeout)
{ {
{ {
SpinLockGuard _(m_arp_table_lock); SpinLockGuard _(m_table_lock);
auto it = m_arp_table.find(ipv4_address); auto it = m_arp_table.find(ipv4_address);
if (it != m_arp_table.end()) if (it != m_arp_table.end())
return it->value; return it->value;
@@ -78,16 +98,8 @@ namespace Kernel
return BAN::Error::from_errno(ETIMEDOUT); return BAN::Error::from_errno(ETIMEDOUT);
} }
BAN::ErrorOr<void> ARPTable::handle_arp_packet(NetworkInterface& interface, BAN::ConstByteSpan buffer) BAN::ErrorOr<void> ARPTable::handle_arp_packet(NetworkInterface& interface, const ARPPacket& packet)
{ {
if (buffer.size() < sizeof(ARPPacket))
{
dwarnln_if(DEBUG_ARP, "Too small ARP packet");
return {};
}
const auto& packet = buffer.as<const ARPPacket>();
if (packet.ptype != EtherType::IPv4) if (packet.ptype != EtherType::IPv4)
{ {
dprintln("Non IPv4 arp packet?"); dprintln("Non IPv4 arp packet?");
@@ -100,24 +112,23 @@ namespace Kernel
{ {
if (packet.tpa == interface.get_ipv4_address()) if (packet.tpa == interface.get_ipv4_address())
{ {
const ARPPacket arp_reply { ARPPacket arp_reply;
.htype = 0x0001, arp_reply.htype = 0x0001;
.ptype = EtherType::IPv4, arp_reply.ptype = EtherType::IPv4;
.hlen = 0x06, arp_reply.hlen = 0x06;
.plen = 0x04, arp_reply.plen = 0x04;
.oper = ARPOperation::Reply, arp_reply.oper = ARPOperation::Reply;
.sha = interface.get_mac_address(), arp_reply.sha = interface.get_mac_address();
.spa = interface.get_ipv4_address(), arp_reply.spa = interface.get_ipv4_address();
.tha = packet.sha, arp_reply.tha = packet.sha;
.tpa = packet.spa, arp_reply.tpa = packet.spa;
};
TRY(interface.send_bytes(packet.sha, EtherType::ARP, BAN::ConstByteSpan::from(arp_reply))); TRY(interface.send_bytes(packet.sha, EtherType::ARP, BAN::ConstByteSpan::from(arp_reply)));
} }
break; break;
} }
case ARPOperation::Reply: case ARPOperation::Reply:
{ {
SpinLockGuard _(m_arp_table_lock); SpinLockGuard _(m_table_lock);
auto it = m_arp_table.find(packet.spa); auto it = m_arp_table.find(packet.spa);
if (it != m_arp_table.end()) if (it != m_arp_table.end())
@@ -143,4 +154,48 @@ namespace Kernel
return {}; return {};
} }
void ARPTable::packet_handle_task()
{
for (;;)
{
PendingArpPacket pending = ({
SpinLockGuard guard(m_pending_lock);
while (m_pending_packets.empty())
{
SpinLockGuardAsMutex smutex(guard);
m_pending_thread_blocker.block_indefinite(&smutex);
}
auto packet = m_pending_packets.front();
m_pending_packets.pop();
packet;
});
if (auto ret = handle_arp_packet(pending.interface, pending.packet); ret.is_error())
dwarnln("{}", ret.error());
}
}
void ARPTable::add_arp_packet(NetworkInterface& interface, BAN::ConstByteSpan buffer)
{
if (buffer.size() < sizeof(ARPPacket))
{
dwarnln_if(DEBUG_ARP, "ARP packet too small");
return;
}
auto& arp_packet = buffer.as<const ARPPacket>();
SpinLockGuard _(m_pending_lock);
if (m_pending_packets.full())
{
dwarnln_if(DEBUG_ARP, "ARP packet queue full");
return;
}
m_pending_packets.push({ .interface = interface, .packet = arp_packet });
m_pending_thread_blocker.unblock();
}
} }

View File

@@ -1,7 +1,6 @@
#include <kernel/IDT.h> #include <kernel/IDT.h>
#include <kernel/InterruptController.h> #include <kernel/InterruptController.h>
#include <kernel/IO.h> #include <kernel/IO.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <kernel/MMIO.h> #include <kernel/MMIO.h>
#include <kernel/Networking/E1000/E1000.h> #include <kernel/Networking/E1000/E1000.h>
@@ -58,11 +57,6 @@ namespace Kernel
E1000::~E1000() E1000::~E1000()
{ {
m_thread_should_die = true;
m_thread_blocker.unblock();
while (!m_thread_is_dead)
Processor::yield();
} }
BAN::ErrorOr<void> E1000::initialize() BAN::ErrorOr<void> E1000::initialize()
@@ -90,16 +84,6 @@ namespace Kernel
dprintln(" link speed: {} Mbps", speed); dprintln(" link speed: {} Mbps", speed);
} }
auto* thread = TRY(Thread::create_kernel([](void* e1000_ptr) {
static_cast<E1000*>(e1000_ptr)->receive_thread();
}, this));
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
{
delete thread;
return ret.release_error();
}
m_thread_is_dead = false;
return {}; return {};
} }
@@ -275,8 +259,10 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer)
{ {
ASSERT(buffer.size() + sizeof(EthernetHeader) <= E1000_TX_BUFFER_SIZE);
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
size_t tx_current = read32(REG_TDT) % E1000_TX_DESCRIPTOR_COUNT; size_t tx_current = read32(REG_TDT) % E1000_TX_DESCRIPTOR_COUNT;
@@ -288,75 +274,48 @@ namespace Kernel
ethernet_header.src_mac = get_mac_address(); ethernet_header.src_mac = get_mac_address();
ethernet_header.ether_type = protocol; ethernet_header.ether_type = protocol;
size_t packet_size = sizeof(EthernetHeader); memcpy(tx_buffer + sizeof(EthernetHeader), buffer.data(), buffer.size());
for (const auto& buffer : payload)
{
ASSERT(packet_size + buffer.size() < E1000_TX_BUFFER_SIZE);
memcpy(tx_buffer + packet_size, buffer.data(), buffer.size());
packet_size += buffer.size();
}
auto& descriptor = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr())[tx_current]; auto& descriptor = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr())[tx_current];
descriptor.length = packet_size; descriptor.length = sizeof(EthernetHeader) + buffer.size();
descriptor.status = 0; descriptor.status = 0;
descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS; descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS;
// FIXME: there isnt really any reason to wait for transmission
write32(REG_TDT, (tx_current + 1) % E1000_TX_DESCRIPTOR_COUNT); write32(REG_TDT, (tx_current + 1) % E1000_TX_DESCRIPTOR_COUNT);
while (descriptor.status == 0) while (descriptor.status == 0)
continue; continue;
dprintln_if(DEBUG_E1000, "sent {} bytes", packet_size); dprintln_if(DEBUG_E1000, "sent {} bytes", sizeof(EthernetHeader) + buffer.size());
return {}; return {};
} }
void E1000::receive_thread()
{
SpinLockGuard _(m_lock);
while (!m_thread_should_die)
{
for (;;)
{
const uint32_t rx_current = (read32(REG_RDT0) + 1) % E1000_RX_DESCRIPTOR_COUNT;
auto& descriptor = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr())[rx_current];
if (!(descriptor.status & 1))
break;
ASSERT(descriptor.length <= E1000_RX_BUFFER_SIZE);
dprintln_if(DEBUG_E1000, "got {} bytes", (uint16_t)descriptor.length);
m_lock.unlock(InterruptState::Enabled);
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),
descriptor.length
});
m_lock.lock();
descriptor.status = 0;
write32(REG_RDT0, rx_current);
}
SpinLockAsMutex smutex(m_lock, InterruptState::Enabled);
m_thread_blocker.block_indefinite(&smutex);
}
m_thread_is_dead = true;
}
void E1000::handle_irq() void E1000::handle_irq()
{ {
const uint32_t icr = read32(REG_ICR); const uint32_t icr = read32(REG_ICR);
if (!(icr & (ICR_RxQ0 | ICR_RXT0)))
return;
write32(REG_ICR, icr); write32(REG_ICR, icr);
if (icr & (ICR_RxQ0 | ICR_RXT0)) SpinLockGuard _(m_lock);
{
SpinLockGuard _(m_lock); for (;;) {
m_thread_blocker.unblock(); uint32_t rx_current = (read32(REG_RDT0) + 1) % E1000_RX_DESCRIPTOR_COUNT;
auto& descriptor = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr())[rx_current];
if (!(descriptor.status & 1))
break;
ASSERT(descriptor.length <= E1000_RX_BUFFER_SIZE);
dprintln_if(DEBUG_E1000, "got {} bytes", (uint16_t)descriptor.length);
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),
descriptor.length
});
descriptor.status = 0;
write32(REG_RDT0, rx_current);
} }
} }

Some files were not shown because too many files have changed in this diff Show More