Compare commits

...

53 Commits

Author SHA1 Message Date
Bananymous 684fa1c4b0 ports: Add pixman port
This fixes cairo dependencies
2026-03-23 17:58:39 +02:00
Bananymous a98d851fde ports: Add gtk3 port 2026-03-23 17:58:39 +02:00
Bananymous 9c3e2dab40 ports: Add pango port 2026-03-23 17:58:39 +02:00
Bananymous eddb68f2fa ports/mesa: Build with x support 2026-03-23 17:55:57 +02:00
Bananymous 791091174a ports/cairo: Build with x support 2026-03-23 17:50:35 +02:00
Bananymous dd9280c6ea ports/expat: Add support for shared libraries 2026-03-23 17:48:19 +02:00
Bananymous a4d83f9fdb ports: Add xbanan port
This allows running x apps on top of my own GUI interface!
2026-03-23 17:47:11 +02:00
Bananymous f42c5c4a5b ports: Add a lot of x library ports + xeyes/xclock 2026-03-23 17:45:59 +02:00
Bananymous 186fa4f1a1 ports: Update git 2.52.0->2.53.0 2026-03-23 17:35:08 +02:00
Bananymous 09292bb87e BAN: Cleanup math code and add SSE sqrt
We should prefer SSE instructions when they are easily available. For
other functions x87 is just simpler. It's hard to write faster and close
to as accurate approximations with SSE.

This does not use xmmintrin.h as clangd does not like that file and
starts throwing errors in every file that includes this :)
2026-03-22 22:07:48 +02:00
Bananymous d18a0de879 Kernel: Fix mprotext for partial regions
if mprotected are did not contain the start of the region, mprotect
would exit early
2026-03-17 23:33:05 +02:00
Bananymous cdc45935b5 Kernel: Don't allow chdir into non-directories 2026-03-17 22:57:17 +02:00
Bananymous 43e18148a6 LibC: Define SSP things 2026-03-17 20:30:25 +02:00
Bananymous b0db645248 LibC: Add basic elf.h 2026-03-17 20:25:38 +02:00
Bananymous 07712758a7 BAN: Add default constructor to ipv4address 2026-03-17 20:24:48 +02:00
Bananymous c1a424a635 Kernel: Implement linux's eventfd 2026-03-17 20:24:06 +02:00
Bananymous a49588dbc7 DynamicLoader: Fix library lookup for already loaded files 2026-03-17 20:05:05 +02:00
Bananymous 1f22b9b982 DynamicLinker: Implement RTLD_NOLOAD 2026-03-17 20:04:48 +02:00
Bananymous 1d07d8e08e LibC/DynamicLoader: Add support for dynamically loaded TLS
Previously I failed to dlopen if any of the objects contained TLS
section
2026-03-17 20:01:51 +02:00
Bananymous 05b2424fca LibC: Implement more proper random number generator 2026-03-17 19:53:43 +02:00
Bananymous 07201c711e LibC: set endp in string to float conversion error 2026-03-17 19:50:12 +02:00
Bananymous 8fac88c9a6 LibC: Add sincos{,f,l} 2026-03-17 19:42:53 +02:00
Bananymous c9aafa78ec DynamicLoader: Fix RO section mprotect arguments 2026-03-05 17:57:03 +02:00
Bananymous e1c337a483 LibC: Fix compile and link flags
We were linking with -nostdlib and manually linked against libgcc. This
does not link with crtbegin and crtend which provides __dso_handle
preventing use of some global C++ constructors inside libc.

Now we just don't link against libc fixing this issue
2026-03-05 16:25:06 +02:00
Bananymous acebe68dfa DynamicLoader: Fix copy relocation and TLS initialization 2026-03-04 23:04:19 +02:00
Bananymous eeef945c25 Kernel: Make tty use the new byte ring buffer 2026-02-28 14:53:15 +02:00
Bananymous a602753bda Kernel: Add front/back/pop_back to ByteRingBuffer 2026-02-28 14:51:35 +02:00
Bananymous 812ae77cd7 Kernel: Make TCP sockets use the new ring buffer
Also fix race condition that sometimes prevented window updates not
being sent after zero window effectively hanging the whole socket
2026-02-28 14:22:08 +02:00
Bananymous 8b8af1a9d9 Kernel: Rewrite pipes using the new ring buffer 2026-02-28 14:20:52 +02:00
Bananymous 493b5cb9b1 Kernel: Implement byte ring buffer
This maps the ring twice right next to each other so we don't have to
care about wrapping around when doing memcpy or accessing the data
2026-02-28 14:18:23 +02:00
Bananymous 1ecd7cc2fe Kernel: Allow protocol specific socket options
I had forgot to remove this condition on the syscall
2026-02-27 19:20:22 +02:00
Bananymous 5c38832456 Kernel: use wake_with_waketime in epoll
We already have the wake time so there is no reason to calculate the
timeout
2026-02-27 19:14:35 +02:00
Bananymous d16f07a547 Kernel: Print thread id when writing to /dev/debug 2026-02-27 19:12:35 +02:00
Bananymous 54acb05131 Kernel: Don't print "./" prefix with debug functions 2026-02-27 19:10:51 +02:00
Bananymous 9ddf19f605 Kernel: Optimize networking code
Remove buffering from network layer and rework loopback interface.
loopback now has a separate recieve thread to allow concurrent sends and
prevent deadlocks
2026-02-27 19:08:08 +02:00
Bananymous ff378e4538 Kernel: Cleanup and optimize TCP
We now only send enough data to fill other ends window, not past that.
Previous logic had a but that allowed sending too much data leading to
retransmissions.

When the target sends zero window and later updates window size,
immediately retransmit non-acknowledged bytes.

Don't validate packets through listeing socket twice. The actual socket
will already verify the checksum so the listening socket does not have
to.
2026-02-24 16:20:23 +02:00
Bananymous 2ea0a24795 Kernel: Fix TCP SYN option propagation
Listening socket now forwards TCP options to the newly created socket
2026-02-23 23:00:47 +02:00
Bananymous acf28d8170 Kernel: Use ring buffers for TCP windows
This speeds up TCP networkign a ton as it doesnt have to do unnecessary
memmoves for each send/receive
2026-02-23 21:10:13 +02:00
Bananymous 666a7bb826 Kernel: Rework TCP window size reporting
We now report actually available window size when sending packets. If
the available window size grows significantly we send an ACK to reflect
this to the remote.
2026-02-23 21:10:13 +02:00
Bananymous 1ac20251cf Kernel: Fix TCP stack crash on retransmission 2026-02-23 17:48:16 +02:00
Bananymous a318a19fe2 LibGUI/WindowServer: Add fullscreen events
When window's fullscreen state changes we now generate events!
2026-02-23 16:06:48 +02:00
Bananymous f4a7aec167 LibGUI/WindowServer: Add support for custom cursor origin 2026-02-23 16:06:48 +02:00
Bananymous 9445332499 Kernel: Remove unnecessary interface lookup
This prevented connecting to local sockets listening on INADDR_ANY
2026-02-23 16:06:48 +02:00
Bananymous 8edd63d115 Kernel: Cleanup {set,get}sockopt debug prints 2026-02-23 16:06:48 +02:00
Bananymous 304ace1172 LibInput: Export keyboard layout keymaps 2026-02-23 16:06:48 +02:00
Bananymous a5cdf0640f BAN: Add value_type to String{,View} 2026-02-23 16:06:48 +02:00
Bananymous 1fc2e43881 BAN: Add support for string format padding 2026-02-23 16:06:48 +02:00
Bananymous 0964c9f928 BAN: Remove unnecessary assert from span 2026-02-23 16:06:48 +02:00
Bananymous 8b1e820869 BAN: Add reallocator support to Vector 2026-02-21 04:03:11 +02:00
Bananymous 9edc6966db BAN: Add reallocator definition
for the moment this does not exist in kernel, kmalloc rewrite soon™️
2026-02-21 04:03:11 +02:00
Bananymous 12207dcb77 BAN: Add is_trivially_copyable trait 2026-02-21 04:03:11 +02:00
Bananymous 2255e36810 LibDEFLATE: Add GZip support
This allows compressing and decompressing with data using GZip headers
and footers
2026-02-21 04:03:11 +02:00
Bananymous 5abddd448e LibC: Fix typo/bug in fnmatch
* would stop matching at '0' instead of end of string
2026-02-19 22:12:59 +02:00
145 changed files with 3865 additions and 954 deletions

View File

@ -9,6 +9,10 @@ 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

@ -6,6 +6,19 @@
#include <float.h> #include <float.h>
// 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
namespace BAN::Math namespace BAN::Math
{ {
@ -167,7 +180,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, 1); const T frac = BAN::Math::fmod<T>(x, (T)1.0);
*iptr = x - frac; *iptr = x - frac;
return frac; return frac;
} }
@ -175,15 +188,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 == 0.0) if (num == (T)0.0)
{ {
*exp = 0; *exp = 0;
return 0.0; return (T)0.0;
} }
T _exp; T e;
asm("fxtract" : "+t"(num), "=u"(_exp)); asm("fxtract" : "+t"(num), "=u"(e));
*exp = (int)_exp + 1; *exp = (int)e + 1;
return num / (T)2.0; return num / (T)2.0;
} }
@ -251,6 +264,7 @@ namespace BAN::Math
"fstp %%st(1);" "fstp %%st(1);"
: "+t"(x) : "+t"(x)
); );
return x; return x;
} }
@ -263,18 +277,9 @@ 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)
{ {
asm( if (x == (T)0.0)
"fyl2x;" return (T)0.0;
"fld1;" return exp2<T>(y * log2<T>(x));
"fld %%st(1);"
"fprem;"
"f2xm1;"
"faddp;"
"fscale;"
: "+t"(x), "+u"(y)
);
return x;
} }
template<floating_point T> template<floating_point T>
@ -309,17 +314,28 @@ 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>)
{
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)); asm("fsqrt" : "+t"(x));
return x; return x;
} }
}
template<floating_point T> template<floating_point T>
inline constexpr T cbrt(T value) inline constexpr T cbrt(T value)
{ {
if (value == 0.0) return pow<T>(value, (T)1.0 / (T)3.0);
return 0.0;
return pow<T>(value, 1.0 / 3.0);
} }
template<floating_point T> template<floating_point T>
@ -346,30 +362,21 @@ namespace BAN::Math
inline constexpr T tan(T x) inline constexpr T tan(T x)
{ {
T one, ret; T one, ret;
asm( asm("fptan" : "=t"(one), "=u"(ret) : "0"(x));
"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( asm("fpatan" : "+t"(x) : "u"(y) : "st(1)");
"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, 1.0); return atan2<T>(x, (T)1.0);
} }
template<floating_point T> template<floating_point T>
@ -378,10 +385,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>
@ -411,7 +418,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);
} }
@ -441,3 +448,8 @@ namespace BAN::Math
} }
} }
#ifdef BAN_MATH_POP_OPTIONS
#undef BAN_MATH_POP_OPTIONS
#pragma GCC pop_options
#endif

View File

@ -9,10 +9,12 @@
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(&deallocator)(void*) = kfree; static constexpr void*(*reallocator)(void*, size_t) = nullptr;
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(&deallocator)(void*) = free; static constexpr void*(*reallocator)(void*, size_t) = realloc;
static constexpr void(*deallocator)(void*) = free;
#endif #endif
} }

View File

@ -69,7 +69,6 @@ namespace BAN
value_type* data() const value_type* data() const
{ {
ASSERT(m_data);
return m_data; return m_data;
} }
@ -84,7 +83,6 @@ 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,6 +14,7 @@ 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;
@ -352,10 +353,9 @@ namespace BAN::Formatter
{ {
template<typename F> template<typename F>
void print_argument(F putc, const String& string, const ValueFormat&) void print_argument(F putc, const String& string, const ValueFormat& format)
{ {
for (String::size_type i = 0; i < string.size(); i++) print_argument(putc, string.sv(), format);
putc(string[i]);
} }
} }

View File

@ -14,6 +14,7 @@ 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:
@ -246,10 +247,12 @@ namespace BAN::Formatter
{ {
template<typename F> template<typename F>
void print_argument(F putc, const StringView& sv, const ValueFormat&) void print_argument(F putc, const StringView& sv, const ValueFormat& format)
{ {
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,6 +61,9 @@ 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

@ -381,10 +381,35 @@ 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);
T* new_data = (T*)BAN::allocator(new_cap * sizeof(T)); const size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
if constexpr (BAN::is_trivially_copyable_v<T>)
{
if constexpr (BAN::reallocator)
{
auto* new_data = static_cast<T*>(BAN::reallocator(m_data, new_cap * sizeof(T)));
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
m_data = new_data;
}
else
{
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
memcpy(new_data, m_data, m_size * sizeof(T));
BAN::deallocator(m_data);
m_data = new_data;
}
}
else
{
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
if (new_data == nullptr) if (new_data == nullptr)
return Error::from_errno(ENOMEM); return Error::from_errno(ENOMEM);
for (size_type i = 0; i < m_size; i++) for (size_type i = 0; i < m_size; i++)
@ -394,6 +419,8 @@ namespace BAN
} }
BAN::deallocator(m_data); BAN::deallocator(m_data);
m_data = new_data; m_data = new_data;
}
m_capacity = new_cap; m_capacity = new_cap;
return {}; return {};
} }

View File

@ -50,6 +50,7 @@ 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

View File

@ -0,0 +1,52 @@
#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

@ -2,6 +2,7 @@
#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
@ -38,7 +39,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_size > 0; } virtual bool can_read_impl() const override { return !m_buffer->empty(); }
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; }
@ -54,9 +55,7 @@ namespace Kernel
timespec m_ctime {}; timespec m_ctime {};
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
BAN::Array<uint8_t, PAGE_SIZE> m_buffer; BAN::UniqPtr<ByteRingBuffer> 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

@ -0,0 +1,76 @@
#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

@ -31,35 +31,18 @@ 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);
void add_arp_packet(NetworkInterface&, BAN::ConstByteSpan); BAN::ErrorOr<void> handle_arp_packet(NetworkInterface&, BAN::ConstByteSpan);
private: private:
ARPTable(); ARPTable() = default;
void packet_handle_task();
BAN::ErrorOr<void> handle_arp_packet(NetworkInterface&, const ARPPacket&);
private: private:
struct PendingArpPacket SpinLock m_arp_table_lock;
{
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();
virtual BAN::MACAddress get_mac_address() const override { return m_mac_address; } BAN::MACAddress get_mac_address() const override { return m_mac_address; }
virtual bool link_up() override { return m_link_up; } bool link_up() override { return m_link_up; }
virtual int link_speed() override; int link_speed() override;
virtual size_t payload_mtu() const override { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); } size_t payload_mtu() const override { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); }
virtual void handle_irq() final override; 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);
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override; BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) override;
virtual bool can_read_impl() const override { return false; } bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; } bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; } bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override { return false; } 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 handle_receive(); void receive_thread();
protected: protected:
PCI::Device& m_pci_device; PCI::Device& m_pci_device;
@ -75,6 +75,10 @@ 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:
virtual void detect_eeprom() override; void detect_eeprom() override;
virtual uint32_t eeprom_read(uint8_t addr) override; uint32_t eeprom_read(uint8_t addr) override;
private: private:
E1000E(PCI::Device& pci_device) E1000E(PCI::Device& pci_device)

View File

@ -38,11 +38,10 @@ 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; }
void add_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan); BAN::ErrorOr<void> handle_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;
@ -55,34 +54,14 @@ 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(); IPv4Layer() = default;
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();
void packet_handle_task();
BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ByteSpan);
private: private:
struct PendingIPv4Packet
{
NetworkInterface& interface;
};
private:
RecursiveSpinLock m_bound_socket_lock;
BAN::UniqPtr<ARPTable> m_arp_table; 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 };
RecursiveSpinLock m_bound_socket_lock;
BAN::HashMap<int, BAN::WeakPtr<NetworkSocket>> m_bound_sockets; BAN::HashMap<int, BAN::WeakPtr<NetworkSocket>> m_bound_sockets;
friend class BAN::UniqPtr<IPv4Layer>; friend class BAN::UniqPtr<IPv4Layer>;

View File

@ -9,6 +9,7 @@ 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();
@ -24,8 +25,9 @@ namespace Kernel
LoopbackInterface() LoopbackInterface()
: NetworkInterface(Type::Loopback) : NetworkInterface(Type::Loopback)
{} {}
~LoopbackInterface();
BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override; BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) 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; }
@ -33,8 +35,27 @@ namespace Kernel
bool has_hungup_impl() const override { return false; } bool has_hungup_impl() const override { return false; }
private: private:
SpinLock m_buffer_lock; void receive_thread();
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,7 +60,11 @@ 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; }
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) = 0; BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan payload)
{
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> extra { 0 }; BAN::NetworkEndian<uint16_t> length { 0 };
}; };
static_assert(sizeof(PseudoHeader) == 12); static_assert(sizeof(PseudoHeader) == 12);
@ -36,6 +36,7 @@ namespace Kernel
NetworkLayer() = default; NetworkLayer() = default;
}; };
uint16_t calculate_internet_checksum(BAN::ConstByteSpan packet, const PseudoHeader& pseudo_header); uint16_t calculate_internet_checksum(BAN::ConstByteSpan buffer);
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 add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) = 0; virtual void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, 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,9 +29,11 @@ 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::ConstByteSpan) override; virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const 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; }
@ -47,7 +49,7 @@ namespace Kernel
void enable_link(); void enable_link();
BAN::ErrorOr<void> enable_interrupt(); BAN::ErrorOr<void> enable_interrupt();
void handle_receive(); void receive_thread();
protected: protected:
PCI::Device& m_pci_device; PCI::Device& m_pci_device;
@ -63,6 +65,9 @@ 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/VirtualRange.h> #include <kernel/Memory/ByteRingBuffer.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,29 +50,30 @@ namespace Kernel
static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, const Info&); static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, const Info&);
~TCPSocket(); ~TCPSocket();
virtual NetworkProtocol protocol() const override { return NetworkProtocol::TCP; } NetworkProtocol protocol() const override { return NetworkProtocol::TCP; }
virtual size_t protocol_header_size() const override { return sizeof(TCPHeader) + m_tcp_options_bytes; } size_t protocol_header_size() const override { return sizeof(TCPHeader) + m_tcp_options_bytes; }
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) override; void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) override;
protected: protected:
virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) override; BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) override;
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override; BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<void> listen_impl(int) override; BAN::ErrorOr<void> listen_impl(int) override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override; BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override; BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override; BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override; BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<void> getsockopt_impl(int, int, void*, 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;
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override; BAN::ErrorOr<long> ioctl_impl(int, void*) override;
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override; void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
virtual bool can_read_impl() const override; bool can_read_impl() const override;
virtual bool can_write_impl() const override; bool can_write_impl() const override;
virtual bool has_error_impl() const override { return false; } bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override; bool has_hungup_impl() const override;
private: private:
enum class State enum class State
@ -96,9 +97,8 @@ namespace Kernel
bool has_ghost_byte { false }; bool has_ghost_byte { false };
uint32_t data_size { 0 }; // number of bytes in this buffer
uint8_t scale_shift { 0 }; // window scale uint8_t scale_shift { 0 }; // window scale
BAN::UniqPtr<VirtualRange> buffer; BAN::UniqPtr<ByteRingBuffer> buffer;
}; };
struct SendWindowInfo struct SendWindowInfo
@ -115,10 +115,10 @@ namespace Kernel
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 data_size { 0 }; // number of bytes in this buffer
uint32_t sent_size { 0 }; // number of bytes in this buffer that have been sent uint32_t sent_size { 0 }; // number of bytes in this buffer that have been sent
BAN::UniqPtr<VirtualRange> buffer; BAN::UniqPtr<ByteRingBuffer> buffer;
}; };
struct ConnectionInfo struct ConnectionInfo
@ -132,6 +132,8 @@ 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
@ -166,8 +168,17 @@ 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,27 +25,28 @@ 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&);
virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; } NetworkProtocol protocol() const override { return NetworkProtocol::UDP; }
virtual size_t protocol_header_size() const override { return sizeof(UDPHeader); } size_t protocol_header_size() const override { return sizeof(UDPHeader); }
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) override; void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) override;
protected: protected:
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override; void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override; BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override; BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override; BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override; BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); } BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); }
virtual BAN::ErrorOr<void> getsockopt_impl(int, int, void*, 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;
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override; BAN::ErrorOr<long> ioctl_impl(int, void*) override;
virtual bool can_read_impl() const override { return !m_packets.empty(); } bool can_read_impl() const override { return !m_packets.empty(); }
virtual bool can_write_impl() const override { return true; } bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; } bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override { return false; } bool has_hungup_impl() const override { return false; }
private: private:
UDPSocket(NetworkLayer&, const Socket::Info&); UDPSocket(NetworkLayer&, const Socket::Info&);

View File

@ -147,6 +147,8 @@ 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);

View File

@ -3,6 +3,7 @@
#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>
@ -102,8 +103,7 @@ namespace Kernel
struct Buffer struct Buffer
{ {
BAN::Array<uint8_t, 1024> buffer; BAN::UniqPtr<ByteRingBuffer> buffer;
size_t bytes { 0 };
bool flush { false }; bool flush { false };
ThreadBlocker thread_blocker; ThreadBlocker thread_blocker;
}; };

View File

@ -335,6 +335,8 @@ 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,10 +21,11 @@ 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

@ -209,7 +209,7 @@ namespace Kernel
continue; continue;
SpinLockGuardAsMutex smutex(guard); SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_or_timeout_ns(m_thread_blocker, waketime_ns - current_ns, false, &smutex)); TRY(Thread::current().block_or_eintr_or_waketime_ns(m_thread_blocker, waketime_ns, false, &smutex));
} }
return event_count; return event_count;

View File

@ -0,0 +1,54 @@
#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

@ -9,12 +9,16 @@
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)
{ {
Pipe* pipe = new Pipe(credentials); auto* pipe_ptr = new Pipe(credentials);
if (pipe == nullptr) if (pipe_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<Inode>::adopt(pipe); auto pipe = BAN::RefPtr<Pipe>::adopt(pipe_ptr);
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)
@ -69,27 +73,16 @@ 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_size == 0) while (m_buffer->empty())
{ {
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);
if (m_buffer_tail + to_copy <= m_buffer.size()) m_buffer->pop(to_copy);
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();
@ -102,7 +95,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_size >= m_buffer.size()) while (m_buffer->full())
{ {
if (m_reading_count == 0) if (m_reading_count == 0)
{ {
@ -112,20 +105,8 @@ 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.size() - m_buffer_size); const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer->free());
const size_t buffer_head = (m_buffer_tail + m_buffer_size) % m_buffer.size(); m_buffer->push(buffer.slice(0, to_copy));
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

@ -0,0 +1,49 @@
#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

@ -17,27 +17,7 @@ namespace Kernel
BAN::ErrorOr<BAN::UniqPtr<ARPTable>> ARPTable::create() BAN::ErrorOr<BAN::UniqPtr<ARPTable>> ARPTable::create()
{ {
auto arp_table = TRY(BAN::UniqPtr<ARPTable>::create()); return 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)
@ -64,7 +44,7 @@ namespace Kernel
ipv4_address = interface.get_gateway(); ipv4_address = interface.get_gateway();
{ {
SpinLockGuard _(m_table_lock); SpinLockGuard _(m_arp_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;
@ -87,7 +67,7 @@ namespace Kernel
while (SystemTimer::get().ms_since_boot() < timeout) while (SystemTimer::get().ms_since_boot() < timeout)
{ {
{ {
SpinLockGuard _(m_table_lock); SpinLockGuard _(m_arp_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;
@ -98,8 +78,16 @@ namespace Kernel
return BAN::Error::from_errno(ETIMEDOUT); return BAN::Error::from_errno(ETIMEDOUT);
} }
BAN::ErrorOr<void> ARPTable::handle_arp_packet(NetworkInterface& interface, const ARPPacket& packet) BAN::ErrorOr<void> ARPTable::handle_arp_packet(NetworkInterface& interface, BAN::ConstByteSpan buffer)
{ {
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?");
@ -112,23 +100,24 @@ namespace Kernel
{ {
if (packet.tpa == interface.get_ipv4_address()) if (packet.tpa == interface.get_ipv4_address())
{ {
ARPPacket arp_reply; const ARPPacket arp_reply {
arp_reply.htype = 0x0001; .htype = 0x0001,
arp_reply.ptype = EtherType::IPv4; .ptype = EtherType::IPv4,
arp_reply.hlen = 0x06; .hlen = 0x06,
arp_reply.plen = 0x04; .plen = 0x04,
arp_reply.oper = ARPOperation::Reply; .oper = ARPOperation::Reply,
arp_reply.sha = interface.get_mac_address(); .sha = interface.get_mac_address(),
arp_reply.spa = interface.get_ipv4_address(); .spa = interface.get_ipv4_address(),
arp_reply.tha = packet.sha; .tha = packet.sha,
arp_reply.tpa = packet.spa; .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_table_lock); SpinLockGuard _(m_arp_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())
@ -154,48 +143,4 @@ 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,6 +1,7 @@
#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>
@ -57,6 +58,11 @@ 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()
@ -84,6 +90,16 @@ 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 {};
} }
@ -259,10 +275,8 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer) BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload)
{ {
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;
@ -274,33 +288,38 @@ 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;
memcpy(tx_buffer + sizeof(EthernetHeader), buffer.data(), buffer.size()); size_t packet_size = sizeof(EthernetHeader);
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 = sizeof(EthernetHeader) + buffer.size(); descriptor.length = packet_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", sizeof(EthernetHeader) + buffer.size()); dprintln_if(DEBUG_E1000, "sent {} bytes", packet_size);
return {}; return {};
} }
void E1000::handle_irq() void E1000::receive_thread()
{ {
const uint32_t icr = read32(REG_ICR);
if (!(icr & (ICR_RxQ0 | ICR_RXT0)))
return;
write32(REG_ICR, icr);
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
for (;;) { while (!m_thread_should_die)
uint32_t rx_current = (read32(REG_RDT0) + 1) % E1000_RX_DESCRIPTOR_COUNT; {
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]; auto& descriptor = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr())[rx_current];
if (!(descriptor.status & 1)) if (!(descriptor.status & 1))
@ -309,14 +328,36 @@ namespace Kernel
dprintln_if(DEBUG_E1000, "got {} bytes", (uint16_t)descriptor.length); dprintln_if(DEBUG_E1000, "got {} bytes", (uint16_t)descriptor.length);
m_lock.unlock(InterruptState::Enabled);
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE), reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),
descriptor.length descriptor.length
}); });
m_lock.lock();
descriptor.status = 0; descriptor.status = 0;
write32(REG_RDT0, rx_current); 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()
{
const uint32_t icr = read32(REG_ICR);
write32(REG_ICR, icr);
if (icr & (ICR_RxQ0 | ICR_RXT0))
{
SpinLockGuard _(m_lock);
m_thread_blocker.unblock();
}
} }
} }

View File

@ -21,50 +21,26 @@ namespace Kernel
BAN::ErrorOr<BAN::UniqPtr<IPv4Layer>> IPv4Layer::create() BAN::ErrorOr<BAN::UniqPtr<IPv4Layer>> IPv4Layer::create()
{ {
auto ipv4_manager = TRY(BAN::UniqPtr<IPv4Layer>::create()); auto ipv4_manager = TRY(BAN::UniqPtr<IPv4Layer>::create());
ipv4_manager->m_thread = TRY(Thread::create_kernel(
[](void* ipv4_manager_ptr)
{
auto& ipv4_manager = *reinterpret_cast<IPv4Layer*>(ipv4_manager_ptr);
ipv4_manager.packet_handle_task();
}, ipv4_manager.ptr()
));
TRY(Processor::scheduler().add_thread(ipv4_manager->m_thread));
ipv4_manager->m_pending_packet_buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(),
KERNEL_OFFSET,
~(uintptr_t)0,
pending_packet_buffer_size,
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
true, false
));
ipv4_manager->m_arp_table = TRY(ARPTable::create()); ipv4_manager->m_arp_table = TRY(ARPTable::create());
return ipv4_manager; return ipv4_manager;
} }
IPv4Layer::IPv4Layer() static IPv4Header get_ipv4_header(size_t packet_size, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol)
{ }
IPv4Layer::~IPv4Layer()
{ {
if (m_thread) IPv4Header header {
m_thread->add_signal(SIGKILL, {}); .version_IHL = 0x45,
m_thread = nullptr; .DSCP_ECN = 0x00,
} .total_length = packet_size,
.identification = 1,
void IPv4Layer::add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol) const .flags_frament = 0x00,
{ .time_to_live = 0x40,
auto& header = packet.as<IPv4Header>(); .protocol = protocol,
header.version_IHL = 0x45; .checksum = 0,
header.DSCP_ECN = 0x00; .src_address = src_ipv4,
header.total_length = packet.size(); .dst_address = dst_ipv4,
header.identification = 1; };
header.flags_frament = 0x00; header.checksum = calculate_internet_checksum(BAN::ConstByteSpan::from(header));
header.time_to_live = 0x40; return header;
header.protocol = protocol;
header.src_address = src_ipv4;
header.dst_address = dst_ipv4;
header.checksum = 0;
header.checksum = calculate_internet_checksum(BAN::ConstByteSpan::from(header), {});
} }
void IPv4Layer::unbind_socket(uint16_t port) void IPv4Layer::unbind_socket(uint16_t port)
@ -204,7 +180,7 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<size_t> IPv4Layer::sendto(NetworkSocket& socket, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len) BAN::ErrorOr<size_t> IPv4Layer::sendto(NetworkSocket& socket, BAN::ConstByteSpan payload, const sockaddr* address, socklen_t address_len)
{ {
if (address->sa_family != AF_INET) if (address->sa_family != AF_INET)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
@ -231,46 +207,63 @@ namespace Kernel
if (!receiver) if (!receiver)
return BAN::Error::from_errno(EADDRNOTAVAIL); return BAN::Error::from_errno(EADDRNOTAVAIL);
TRY(socket.interface(receiver->address(), receiver->address_len()));
} }
BAN::Vector<uint8_t> packet_buffer; const auto ipv4_header = get_ipv4_header(
TRY(packet_buffer.resize(buffer.size() + sizeof(IPv4Header) + socket.protocol_header_size())); sizeof(IPv4Header) + socket.protocol_header_size() + payload.size(),
auto packet = BAN::ByteSpan { packet_buffer.span() };
auto pseudo_header = PseudoHeader {
.src_ipv4 = interface->get_ipv4_address(),
.dst_ipv4 = dst_ipv4,
.protocol = socket.protocol()
};
memcpy(
packet.slice(sizeof(IPv4Header)).slice(socket.protocol_header_size()).data(),
buffer.data(),
buffer.size()
);
socket.add_protocol_header(
packet.slice(sizeof(IPv4Header)),
dst_port,
pseudo_header
);
add_ipv4_header(
packet,
interface->get_ipv4_address(), interface->get_ipv4_address(),
dst_ipv4, dst_ipv4,
socket.protocol() socket.protocol()
); );
TRY(interface->send_bytes(dst_mac, EtherType::IPv4, packet)); const auto pseudo_header = PseudoHeader {
.src_ipv4 = interface->get_ipv4_address(),
.dst_ipv4 = dst_ipv4,
.protocol = socket.protocol(),
.length = socket.protocol_header_size() + payload.size()
};
return buffer.size(); uint8_t protocol_header_buffer[32];
ASSERT(socket.protocol_header_size() < sizeof(protocol_header_buffer));
auto protocol_header = BAN::ByteSpan::from(protocol_header_buffer).slice(0, socket.protocol_header_size());
socket.get_protocol_header(protocol_header, payload, dst_port, pseudo_header);
BAN::ConstByteSpan buffers[] {
BAN::ConstByteSpan::from(ipv4_header),
protocol_header,
payload,
};
TRY(interface->send_bytes(dst_mac, EtherType::IPv4, { buffers, sizeof(buffers) / sizeof(*buffers) }));
return payload.size();
} }
BAN::ErrorOr<void> IPv4Layer::handle_ipv4_packet(NetworkInterface& interface, BAN::ByteSpan packet) BAN::ErrorOr<void> IPv4Layer::handle_ipv4_packet(NetworkInterface& interface, BAN::ConstByteSpan packet)
{ {
ASSERT(packet.size() >= sizeof(IPv4Header)); if (packet.size() < sizeof(IPv4Header))
{
dwarnln_if(DEBUG_IPV4, "Too small IPv4 packet");
return {};
}
auto& ipv4_header = packet.as<const IPv4Header>(); auto& ipv4_header = packet.as<const IPv4Header>();
auto ipv4_data = packet.slice(sizeof(IPv4Header)); if (calculate_internet_checksum(BAN::ConstByteSpan::from(ipv4_header)) != 0)
{
dwarnln_if(DEBUG_IPV4, "IPv4 packet checksum failed");
return {};
}
if (ipv4_header.total_length > packet.size() || ipv4_header.total_length > interface.payload_mtu() || ipv4_header.total_length < sizeof(IPv4Header))
{
if (ipv4_header.flags_frament & IPv4Flags::DF)
dwarnln_if(DEBUG_IPV4, "Invalid IPv4 packet");
else
dwarnln_if(DEBUG_IPV4, "IPv4 fragmentation not supported");
return {};
}
auto ipv4_data = packet.slice(0, ipv4_header.total_length).slice(sizeof(IPv4Header));
auto src_ipv4 = ipv4_header.src_address; auto src_ipv4 = ipv4_header.src_address;
@ -293,14 +286,33 @@ namespace Kernel
{ {
auto dst_mac = TRY(m_arp_table->get_mac_from_ipv4(interface, src_ipv4)); auto dst_mac = TRY(m_arp_table->get_mac_from_ipv4(interface, src_ipv4));
auto& reply_icmp_header = ipv4_data.as<ICMPHeader>(); auto send_ipv4_header = get_ipv4_header(
reply_icmp_header.type = ICMPType::EchoReply; ipv4_data.size(),
reply_icmp_header.checksum = 0; interface.get_ipv4_address(),
reply_icmp_header.checksum = calculate_internet_checksum(ipv4_data, {}); src_ipv4,
NetworkProtocol::ICMP
);
add_ipv4_header(packet, interface.get_ipv4_address(), src_ipv4, NetworkProtocol::ICMP); ICMPHeader send_icmp_header {
.type = ICMPType::EchoReply,
.code = icmp_header.code,
.checksum = 0,
.rest = icmp_header.rest,
};
auto send_payload = ipv4_data.slice(sizeof(ICMPHeader));
const BAN::ConstByteSpan send_buffers[] {
BAN::ConstByteSpan::from(send_ipv4_header),
BAN::ConstByteSpan::from(send_icmp_header),
send_payload
};
auto send_buffers_span = BAN::Span { send_buffers, sizeof(send_buffers) / sizeof(*send_buffers) };
send_icmp_header.checksum = calculate_internet_checksum(send_buffers_span.slice(1));
TRY(interface.send_bytes(dst_mac, EtherType::IPv4, send_buffers_span));
TRY(interface.send_bytes(dst_mac, EtherType::IPv4, packet));
break; break;
} }
case ICMPType::DestinationUnreachable: case ICMPType::DestinationUnreachable:
@ -382,80 +394,4 @@ namespace Kernel
return {}; return {};
} }
void IPv4Layer::packet_handle_task()
{
for (;;)
{
PendingIPv4Packet 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;
});
uint8_t* buffer_start = reinterpret_cast<uint8_t*>(m_pending_packet_buffer->vaddr());
const size_t ipv4_packet_size = reinterpret_cast<const IPv4Header*>(buffer_start)->total_length;
if (auto ret = handle_ipv4_packet(pending.interface, BAN::ByteSpan(buffer_start, ipv4_packet_size)); ret.is_error())
dwarnln_if(DEBUG_IPV4, "{}", ret.error());
SpinLockGuard _(m_pending_lock);
m_pending_total_size -= ipv4_packet_size;
if (m_pending_total_size)
memmove(buffer_start, buffer_start + ipv4_packet_size, m_pending_total_size);
}
}
void IPv4Layer::add_ipv4_packet(NetworkInterface& interface, BAN::ConstByteSpan buffer)
{
if (buffer.size() < sizeof(IPv4Header))
{
dwarnln_if(DEBUG_IPV4, "IPv4 packet too small");
return;
}
SpinLockGuard _(m_pending_lock);
if (m_pending_packets.full())
{
dwarnln_if(DEBUG_IPV4, "IPv4 packet queue full");
return;
}
if (m_pending_total_size + buffer.size() > m_pending_packet_buffer->size())
{
dwarnln_if(DEBUG_IPV4, "IPv4 packet queue full");
return;
}
auto& ipv4_header = buffer.as<const IPv4Header>();
if (calculate_internet_checksum(BAN::ConstByteSpan::from(ipv4_header), {}) != 0)
{
dwarnln_if(DEBUG_IPV4, "Invalid IPv4 packet");
return;
}
if (ipv4_header.total_length > buffer.size() || ipv4_header.total_length > interface.payload_mtu())
{
if (ipv4_header.flags_frament & IPv4Flags::DF)
dwarnln_if(DEBUG_IPV4, "Invalid IPv4 packet");
else
dwarnln_if(DEBUG_IPV4, "IPv4 fragmentation not supported");
return;
}
uint8_t* buffer_start = reinterpret_cast<uint8_t*>(m_pending_packet_buffer->vaddr());
memcpy(buffer_start + m_pending_total_size, buffer.data(), ipv4_header.total_length);
m_pending_total_size += ipv4_header.total_length;
m_pending_packets.push({ .interface = interface });
m_pending_thread_blocker.unblock();
}
} }

View File

@ -1,3 +1,4 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Networking/Loopback.h> #include <kernel/Networking/Loopback.h>
#include <kernel/Networking/NetworkManager.h> #include <kernel/Networking/NetworkManager.h>
@ -10,40 +11,121 @@ namespace Kernel
if (loopback_ptr == nullptr) if (loopback_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto loopback = BAN::RefPtr<LoopbackInterface>::adopt(loopback_ptr); auto loopback = BAN::RefPtr<LoopbackInterface>::adopt(loopback_ptr);
loopback->m_buffer = TRY(VirtualRange::create_to_vaddr_range( loopback->m_buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(), PageTable::kernel(),
KERNEL_OFFSET, KERNEL_OFFSET,
BAN::numeric_limits<vaddr_t>::max(), BAN::numeric_limits<vaddr_t>::max(),
buffer_size, buffer_size * buffer_count,
PageTable::Flags::ReadWrite | PageTable::Flags::Present, PageTable::Flags::ReadWrite | PageTable::Flags::Present,
true, false true, false
)); ));
auto* thread = TRY(Thread::create_kernel([](void* loopback_ptr) {
static_cast<LoopbackInterface*>(loopback_ptr)->receive_thread();
}, loopback_ptr));
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
{
delete thread;
return ret.release_error();
}
loopback->m_thread_is_dead = false;
loopback->set_ipv4_address({ 127, 0, 0, 1 }); loopback->set_ipv4_address({ 127, 0, 0, 1 });
loopback->set_netmask({ 255, 0, 0, 0 }); loopback->set_netmask({ 255, 0, 0, 0 });
for (size_t i = 0; i < buffer_count; i++)
{
loopback->m_descriptors[i] = {
.addr = reinterpret_cast<uint8_t*>(loopback->m_buffer->vaddr()) + i * buffer_size,
.size = 0,
.state = 0,
};
}
return loopback; return loopback;
} }
BAN::ErrorOr<void> LoopbackInterface::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer) LoopbackInterface::~LoopbackInterface()
{ {
ASSERT(buffer.size() + sizeof(EthernetHeader) <= buffer_size); m_thread_should_die = true;
m_thread_blocker.unblock();
SpinLockGuard _(m_buffer_lock); while (!m_thread_is_dead)
Processor::yield();
}
uint8_t* buffer_vaddr = reinterpret_cast<uint8_t*>(m_buffer->vaddr()); BAN::ErrorOr<void> LoopbackInterface::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload)
{
auto& descriptor =
[&]() -> Descriptor&
{
LockGuard _(m_buffer_lock);
for (;;)
{
auto& descriptor = m_descriptors[m_buffer_head];
if (descriptor.state == 0)
{
m_buffer_head = (m_buffer_head + 1) % buffer_count;
descriptor.state = 1;
return descriptor;
}
m_thread_blocker.block_indefinite(&m_buffer_lock);
}
}();
auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(buffer_vaddr); auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(descriptor.addr);
ethernet_header.dst_mac = destination; ethernet_header.dst_mac = destination;
ethernet_header.src_mac = get_mac_address(); ethernet_header.src_mac = get_mac_address();
ethernet_header.ether_type = protocol; ethernet_header.ether_type = protocol;
memcpy(buffer_vaddr + sizeof(EthernetHeader), buffer.data(), buffer.size()); size_t packet_size = sizeof(EthernetHeader);
for (const auto& buffer : payload)
{
ASSERT(packet_size + buffer.size() <= buffer_size);
memcpy(descriptor.addr + packet_size, buffer.data(), buffer.size());
packet_size += buffer.size();
}
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { LockGuard _(m_buffer_lock);
buffer_vaddr, descriptor.size = packet_size;
buffer.size() + sizeof(EthernetHeader) descriptor.state = 2;
}); m_thread_blocker.unblock();
return {}; return {};
} }
void LoopbackInterface::receive_thread()
{
LockGuard _(m_buffer_lock);
while (!m_thread_should_die)
{
for (;;)
{
auto& descriptor = m_descriptors[m_buffer_tail];
if (descriptor.state != 2)
break;
m_buffer_tail = (m_buffer_tail + 1) % buffer_count;
m_buffer_lock.unlock();
NetworkManager::get().on_receive(*this, {
descriptor.addr,
descriptor.size,
});
m_buffer_lock.lock();
descriptor.size = 0;
descriptor.state = 0;
m_thread_blocker.unblock();
}
m_thread_blocker.block_indefinite(&m_buffer_lock);
}
m_thread_is_dead = true;
}
} }

View File

@ -3,15 +3,28 @@
namespace Kernel namespace Kernel
{ {
uint16_t calculate_internet_checksum(BAN::ConstByteSpan packet, const PseudoHeader& pseudo_header) uint16_t calculate_internet_checksum(BAN::ConstByteSpan buffer)
{
return calculate_internet_checksum({ &buffer, 1 });
}
uint16_t calculate_internet_checksum(BAN::Span<const BAN::ConstByteSpan> buffers)
{ {
uint32_t checksum = 0; uint32_t checksum = 0;
for (size_t i = 0; i < sizeof(pseudo_header) / sizeof(uint16_t); i++)
checksum += BAN::host_to_network_endian(reinterpret_cast<const uint16_t*>(&pseudo_header)[i]); for (size_t i = 0; i < buffers.size(); i++)
for (size_t i = 0; i < packet.size() / sizeof(uint16_t); i++) {
checksum += BAN::host_to_network_endian(reinterpret_cast<const uint16_t*>(packet.data())[i]); auto buffer = buffers[i];
if (packet.size() % 2)
checksum += (uint16_t)packet[packet.size() - 1] << 8; const uint16_t* buffer_u16 = reinterpret_cast<const uint16_t*>(buffer.data());
for (size_t j = 0; j < buffer.size() / 2; j++)
checksum += BAN::host_to_network_endian(buffer_u16[j]);
if (buffer.size() % 2 == 0)
continue;
ASSERT(i == buffers.size() - 1);
checksum += buffer[buffer.size() - 1] << 8;
}
while (checksum >> 16) while (checksum >> 16)
checksum = (checksum >> 16) + (checksum & 0xFFFF); checksum = (checksum >> 16) + (checksum & 0xFFFF);
return ~(uint16_t)checksum; return ~(uint16_t)checksum;

View File

@ -154,18 +154,18 @@ namespace Kernel
return; return;
auto ethernet_header = packet.as<const EthernetHeader>(); auto ethernet_header = packet.as<const EthernetHeader>();
auto packet_data = packet.slice(sizeof(EthernetHeader));
switch (ethernet_header.ether_type) switch (ethernet_header.ether_type)
{ {
case EtherType::ARP: case EtherType::ARP:
{ if (auto ret = m_ipv4_layer->arp_table().handle_arp_packet(interface, packet_data); ret.is_error())
m_ipv4_layer->arp_table().add_arp_packet(interface, packet.slice(sizeof(EthernetHeader))); dwarnln("ARP: {}", ret.error());
break; break;
}
case EtherType::IPv4: case EtherType::IPv4:
{ if (auto ret = m_ipv4_layer->handle_ipv4_packet(interface, packet_data); ret.is_error())
m_ipv4_layer->add_ipv4_packet(interface, packet.slice(sizeof(EthernetHeader))); dwarnln("IPv4; {}", ret.error());
break; break;
}
default: default:
dprintln_if(DEBUG_ETHERTYPE, "Unknown EtherType 0x{4H}", (uint16_t)ethernet_header.ether_type); dprintln_if(DEBUG_ETHERTYPE, "Unknown EtherType 0x{4H}", (uint16_t)ethernet_header.ether_type);
break; break;

View File

@ -7,6 +7,9 @@
namespace Kernel namespace Kernel
{ {
// each buffer is 7440 bytes + padding = 8192
constexpr size_t s_buffer_size = 8192;
bool RTL8169::probe(PCI::Device& pci_device) bool RTL8169::probe(PCI::Device& pci_device)
{ {
if (pci_device.vendor_id() != 0x10ec) if (pci_device.vendor_id() != 0x10ec)
@ -68,9 +71,28 @@ namespace Kernel
// lock config registers // lock config registers
m_io_bar_region->write8(RTL8169_IO_9346CR, RTL8169_9346CR_MODE_NORMAL); m_io_bar_region->write8(RTL8169_IO_9346CR, RTL8169_9346CR_MODE_NORMAL);
auto* thread = TRY(Thread::create_kernel([](void* rtl8169_ptr) {
static_cast<RTL8169*>(rtl8169_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 {};
} }
RTL8169::~RTL8169()
{
m_thread_should_die = true;
m_thread_blocker.unblock();
while (!m_thread_is_dead)
Processor::yield();
}
BAN::ErrorOr<void> RTL8169::reset() BAN::ErrorOr<void> RTL8169::reset()
{ {
m_io_bar_region->write8(RTL8169_IO_CR, RTL8169_CR_RST); m_io_bar_region->write8(RTL8169_IO_CR, RTL8169_CR_RST);
@ -85,15 +107,12 @@ namespace Kernel
BAN::ErrorOr<void> RTL8169::initialize_rx() BAN::ErrorOr<void> RTL8169::initialize_rx()
{ {
// each buffer is 7440 bytes + padding = 8192 m_rx_buffer_region = TRY(DMARegion::create(m_rx_descriptor_count * s_buffer_size));
constexpr size_t buffer_size = 2 * PAGE_SIZE;
m_rx_buffer_region = TRY(DMARegion::create(m_rx_descriptor_count * buffer_size));
m_rx_descriptor_region = TRY(DMARegion::create(m_rx_descriptor_count * sizeof(RTL8169Descriptor))); m_rx_descriptor_region = TRY(DMARegion::create(m_rx_descriptor_count * sizeof(RTL8169Descriptor)));
for (size_t i = 0; i < m_rx_descriptor_count; i++) for (size_t i = 0; i < m_rx_descriptor_count; i++)
{ {
const paddr_t rx_buffer_paddr = m_rx_buffer_region->paddr() + i * buffer_size; const paddr_t rx_buffer_paddr = m_rx_buffer_region->paddr() + i * s_buffer_size;
uint32_t command = 0x1FF8 | RTL8169_DESC_CMD_OWN; uint32_t command = 0x1FF8 | RTL8169_DESC_CMD_OWN;
if (i == m_rx_descriptor_count - 1) if (i == m_rx_descriptor_count - 1)
@ -120,21 +139,17 @@ namespace Kernel
// configure max rx packet size // configure max rx packet size
m_io_bar_region->write16(RTL8169_IO_RMS, RTL8169_RMS_MAX); m_io_bar_region->write16(RTL8169_IO_RMS, RTL8169_RMS_MAX);
return {}; return {};
} }
BAN::ErrorOr<void> RTL8169::initialize_tx() BAN::ErrorOr<void> RTL8169::initialize_tx()
{ {
// each buffer is 7440 bytes + padding = 8192 m_tx_buffer_region = TRY(DMARegion::create(m_tx_descriptor_count * s_buffer_size));
constexpr size_t buffer_size = 2 * PAGE_SIZE;
m_tx_buffer_region = TRY(DMARegion::create(m_tx_descriptor_count * buffer_size));
m_tx_descriptor_region = TRY(DMARegion::create(m_tx_descriptor_count * sizeof(RTL8169Descriptor))); m_tx_descriptor_region = TRY(DMARegion::create(m_tx_descriptor_count * sizeof(RTL8169Descriptor)));
for (size_t i = 0; i < m_tx_descriptor_count; i++) for (size_t i = 0; i < m_tx_descriptor_count; i++)
{ {
const paddr_t tx_buffer_paddr = m_tx_buffer_region->paddr() + i * buffer_size; const paddr_t tx_buffer_paddr = m_tx_buffer_region->paddr() + i * s_buffer_size;
uint32_t command = 0; uint32_t command = 0;
if (i == m_tx_descriptor_count - 1) if (i == m_tx_descriptor_count - 1)
@ -194,14 +209,8 @@ namespace Kernel
return 0; return 0;
} }
BAN::ErrorOr<void> RTL8169::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer) BAN::ErrorOr<void> RTL8169::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload)
{ {
constexpr size_t buffer_size = 8192;
const uint16_t packet_size = sizeof(EthernetHeader) + buffer.size();
if (packet_size > buffer_size)
return BAN::Error::from_errno(EINVAL);
if (!link_up()) if (!link_up())
return BAN::Error::from_errno(EADDRNOTAVAIL); return BAN::Error::from_errno(EADDRNOTAVAIL);
@ -219,14 +228,20 @@ namespace Kernel
m_lock.unlock(state); m_lock.unlock(state);
auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + tx_current * buffer_size); auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + tx_current * s_buffer_size);
// write packet // write packet
auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(tx_buffer); auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(tx_buffer);
ethernet_header.dst_mac = destination; ethernet_header.dst_mac = destination;
ethernet_header.src_mac = get_mac_address(); ethernet_header.src_mac = get_mac_address();
ethernet_header.ether_type = protocol; ethernet_header.ether_type = protocol;
memcpy(tx_buffer + sizeof(EthernetHeader), buffer.data(), buffer.size());
size_t packet_size = sizeof(EthernetHeader);
for (const auto& buffer : payload)
{
memcpy(tx_buffer + packet_size, buffer.data(), buffer.size());
packet_size += buffer.size();
}
// give packet ownership to NIC // give packet ownership to NIC
uint32_t command = packet_size | RTL8169_DESC_CMD_OWN | RTL8169_DESC_CMD_LS | RTL8169_DESC_CMD_FS; uint32_t command = packet_size | RTL8169_DESC_CMD_OWN | RTL8169_DESC_CMD_LS | RTL8169_DESC_CMD_FS;
@ -240,6 +255,50 @@ namespace Kernel
return {}; return {};
} }
void RTL8169::receive_thread()
{
SpinLockGuard _(m_lock);
while (!m_thread_should_die)
{
for (;;)
{
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[m_rx_current];
if (descriptor.command & RTL8169_DESC_CMD_OWN)
break;
// packet buffer can only hold single packet, so we should not receive any multi-descriptor packets
ASSERT((descriptor.command & RTL8169_DESC_CMD_LS) && (descriptor.command & RTL8169_DESC_CMD_FS));
const uint16_t packet_length = descriptor.command & 0x3FFF;
if (packet_length > s_buffer_size)
dwarnln("Got {} bytes to {} byte buffer", packet_length, s_buffer_size);
else if (descriptor.command & (1u << 21))
; // descriptor has an error
else
{
m_lock.unlock(InterruptState::Enabled);
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + m_rx_current * s_buffer_size),
packet_length
});
m_lock.lock();
}
m_rx_current = (m_rx_current + 1) % m_rx_descriptor_count;
descriptor.command = descriptor.command | RTL8169_DESC_CMD_OWN;
}
SpinLockAsMutex smutex(m_lock, InterruptState::Enabled);
m_thread_blocker.block_indefinite(&smutex);
}
m_thread_is_dead = true;
}
void RTL8169::handle_irq() void RTL8169::handle_irq()
{ {
const uint16_t interrupt_status = m_io_bar_region->read16(RTL8169_IO_ISR); const uint16_t interrupt_status = m_io_bar_region->read16(RTL8169_IO_ISR);
@ -251,7 +310,7 @@ namespace Kernel
dprintln("link status -> {}", m_link_up.load()); dprintln("link status -> {}", m_link_up.load());
} }
if (interrupt_status & RTL8169_IR_TOK) if (interrupt_status & (RTL8169_IR_TOK | RTL8169_IR_ROK))
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
m_thread_blocker.unblock(); m_thread_blocker.unblock();
@ -266,38 +325,6 @@ namespace Kernel
if (interrupt_status & RTL8169_IR_FVOW) if (interrupt_status & RTL8169_IR_FVOW)
dwarnln("Rx FIFO overflow"); dwarnln("Rx FIFO overflow");
// dont log TDU is sent after each sent packet // dont log TDU is sent after each sent packet
if (!(interrupt_status & RTL8169_IR_ROK))
return;
constexpr size_t buffer_size = 8192;
for (;;)
{
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[m_rx_current];
if (descriptor.command & RTL8169_DESC_CMD_OWN)
break;
// packet buffer can only hold single packet, so we should not receive any multi-descriptor packets
ASSERT((descriptor.command & RTL8169_DESC_CMD_LS) && (descriptor.command & RTL8169_DESC_CMD_FS));
const uint16_t packet_length = descriptor.command & 0x3FFF;
if (packet_length > buffer_size)
dwarnln("Got {} bytes to {} byte buffer", packet_length, buffer_size);
else if (descriptor.command & (1u << 21))
; // descriptor has an error
else
{
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + m_rx_current * buffer_size),
packet_length
});
}
m_rx_current = (m_rx_current + 1) % m_rx_descriptor_count;
descriptor.command = descriptor.command | RTL8169_DESC_CMD_OWN;
}
} }
} }

View File

@ -7,6 +7,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -24,26 +25,19 @@ namespace Kernel
static constexpr size_t s_recv_window_buffer_size = 16 * PAGE_SIZE; static constexpr size_t s_recv_window_buffer_size = 16 * PAGE_SIZE;
static constexpr size_t s_send_window_buffer_size = 16 * PAGE_SIZE; static constexpr size_t s_send_window_buffer_size = 16 * PAGE_SIZE;
// allows upto 1 MiB windows
static constexpr uint8_t s_window_shift = 4;
// https://www.rfc-editor.org/rfc/rfc1122 4.2.2.6
static constexpr uint16_t s_default_mss = 536;
BAN::ErrorOr<BAN::RefPtr<TCPSocket>> TCPSocket::create(NetworkLayer& network_layer, const Info& info) BAN::ErrorOr<BAN::RefPtr<TCPSocket>> TCPSocket::create(NetworkLayer& network_layer, const Info& info)
{ {
auto socket = TRY(BAN::RefPtr<TCPSocket>::create(network_layer, info)); auto socket = TRY(BAN::RefPtr<TCPSocket>::create(network_layer, info));
socket->m_recv_window.buffer = TRY(VirtualRange::create_to_vaddr_range( socket->m_last_sent_window_size = s_recv_window_buffer_size;
PageTable::kernel(), socket->m_recv_window.buffer = TRY(ByteRingBuffer::create(s_recv_window_buffer_size));
KERNEL_OFFSET, socket->m_recv_window.scale_shift = s_window_shift;
~(vaddr_t)0, socket->m_send_window.buffer = TRY(ByteRingBuffer::create(s_send_window_buffer_size));
s_recv_window_buffer_size,
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
true, false
));
socket->m_recv_window.scale_shift = PAGE_SIZE_SHIFT; // use PAGE_SIZE windows
socket->m_send_window.buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(),
KERNEL_OFFSET,
~(vaddr_t)0,
s_send_window_buffer_size,
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
true, false
));
socket->m_thread = TRY(Thread::create_kernel( socket->m_thread = TRY(Thread::create_kernel(
[](void* socket_ptr) [](void* socket_ptr)
{ {
@ -100,12 +94,13 @@ namespace Kernel
return_inode->m_listen_parent = this; return_inode->m_listen_parent = this;
return_inode->m_connection_info.emplace(connection.target); return_inode->m_connection_info.emplace(connection.target);
return_inode->m_recv_window.start_seq = connection.target_start_seq; return_inode->m_recv_window.start_seq = connection.target_start_seq;
return_inode->m_send_window.scale_shift = connection.window_scale;
return_inode->m_send_window.mss = connection.maximum_seqment_size;
return_inode->m_next_flags = SYN | ACK; return_inode->m_next_flags = SYN | ACK;
return_inode->m_next_state = State::SynReceived; return_inode->m_next_state = State::SynReceived;
return_inode->m_mutex.unlock();
if (!return_inode->m_connection_info->has_window_scale) if (!return_inode->m_connection_info->has_window_scale)
return_inode->m_recv_window.scale_shift = 0; return_inode->m_recv_window.scale_shift = 0;
return_inode->m_mutex.unlock();
TRY(m_listen_children.emplace(listen_key, return_inode)); TRY(m_listen_children.emplace(listen_key, return_inode));
@ -197,8 +192,7 @@ namespace Kernel
BAN::ErrorOr<size_t> TCPSocket::recvmsg_impl(msghdr& message, int flags) BAN::ErrorOr<size_t> TCPSocket::recvmsg_impl(msghdr& message, int flags)
{ {
flags &= (MSG_OOB | MSG_PEEK | MSG_WAITALL); if (flags & ~(MSG_PEEK))
if (flags != 0)
{ {
dwarnln("TODO: recvmsg with flags 0x{H}", flags); dwarnln("TODO: recvmsg with flags 0x{H}", flags);
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
@ -206,14 +200,14 @@ namespace Kernel
if (CMSG_FIRSTHDR(&message)) if (CMSG_FIRSTHDR(&message))
{ {
dwarnln("ignoring recvmsg control message"); dprintln_if(DEBUG_TCP, "ignoring recvmsg control message");
message.msg_controllen = 0; message.msg_controllen = 0;
} }
if (!m_has_connected) if (!m_has_connected)
return BAN::Error::from_errno(ENOTCONN); return BAN::Error::from_errno(ENOTCONN);
while (m_recv_window.data_size == 0) while (m_recv_window.buffer->empty())
{ {
if (m_state != State::Established) if (m_state != State::Established)
return return_with_maybe_zero(); return return_with_maybe_zero();
@ -223,21 +217,34 @@ namespace Kernel
message.msg_flags = 0; message.msg_flags = 0;
size_t total_recv = 0; size_t total_recv = 0;
for (int i = 0; i < message.msg_iovlen; i++) for (int i = 0; i < message.msg_iovlen && total_recv < m_recv_window.buffer->size(); i++)
{ {
auto* recv_buffer = reinterpret_cast<uint8_t*>(m_recv_window.buffer->vaddr()); auto& iov = message.msg_iov[i];
const size_t nrecv = BAN::Math::min<size_t>(message.msg_iov[i].iov_len, m_recv_window.data_size); const size_t nrecv = BAN::Math::min(iov.iov_len, m_recv_window.buffer->size() - total_recv);
memcpy(message.msg_iov[i].iov_base, recv_buffer, nrecv); memcpy(iov.iov_base, m_recv_window.buffer->get_data().data() + total_recv, nrecv);
total_recv += nrecv; total_recv += nrecv;
m_recv_window.data_size -= nrecv; }
m_recv_window.start_seq += nrecv;
if (m_recv_window.data_size == 0)
break;
// TODO: use circular buffer to avoid this if (!(flags & MSG_PEEK))
memmove(recv_buffer, recv_buffer + nrecv, m_recv_window.data_size); {
m_recv_window.buffer->pop(total_recv);
m_recv_window.start_seq += total_recv;
}
const size_t update_window_threshold = m_recv_window.buffer->capacity() / 8;
const bool should_update_window_size =
m_last_sent_window_size != m_recv_window.buffer->capacity() && (
(m_last_sent_window_size == 0) ||
(m_recv_window.buffer->empty()) ||
(m_last_sent_window_size + update_window_threshold <= m_recv_window.buffer->free())
);
if (should_update_window_size || m_should_send_zero_window)
{
m_should_send_window_update = true;
m_thread_blocker.unblock();
} }
return total_recv; return total_recv;
@ -257,7 +264,7 @@ namespace Kernel
if (!m_has_connected) if (!m_has_connected)
return BAN::Error::from_errno(ENOTCONN); return BAN::Error::from_errno(ENOTCONN);
while (m_send_window.data_size == m_send_window.buffer->size()) while (m_send_window.buffer->full())
{ {
if (m_state != State::Established) if (m_state != State::Established)
return return_with_maybe_zero(); return return_with_maybe_zero();
@ -267,17 +274,14 @@ namespace Kernel
} }
size_t total_sent = 0; size_t total_sent = 0;
for (int i = 0; i < message.msg_iovlen; i++) for (int i = 0; i < message.msg_iovlen && !m_send_window.buffer->full(); i++)
{ {
auto* send_buffer = reinterpret_cast<uint8_t*>(m_send_window.buffer->vaddr()); const auto& iov = message.msg_iov[i];
const size_t nsend = BAN::Math::min<size_t>(message.msg_iov[i].iov_len, m_send_window.buffer->size() - m_send_window.data_size); const size_t nsend = BAN::Math::min(iov.iov_len, m_send_window.buffer->free());
memcpy(send_buffer + m_send_window.data_size, message.msg_iov[i].iov_base, nsend); m_send_window.buffer->push({ static_cast<const uint8_t*>(iov.iov_base), nsend });
total_sent += nsend; total_sent += nsend;
m_send_window.data_size += nsend;
if (m_send_window.data_size == m_send_window.buffer->size())
break;
} }
m_thread_blocker.unblock(); m_thread_blocker.unblock();
@ -298,12 +302,16 @@ namespace Kernel
BAN::ErrorOr<void> TCPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len) BAN::ErrorOr<void> TCPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len)
{ {
if (level != SOL_SOCKET)
return BAN::Error::from_errno(EINVAL);
int result; int result;
switch (level)
{
case SOL_SOCKET:
switch (option) switch (option)
{ {
case SO_KEEPALIVE:
result = m_keep_alive;
break;
case SO_ERROR: case SO_ERROR:
result = 0; result = 0;
break; break;
@ -311,10 +319,27 @@ namespace Kernel
result = m_send_window.scaled_size(); result = m_send_window.scaled_size();
break; break;
case SO_RCVBUF: case SO_RCVBUF:
result = m_recv_window.buffer->size(); result = m_recv_window.buffer->capacity();
break; break;
default: default:
return BAN::Error::from_errno(ENOTSUP); dwarnln("getsockopt(SOL_SOCKET, {})", option);
return BAN::Error::from_errno(ENOPROTOOPT);
}
break;
case IPPROTO_TCP:
switch (option)
{
case TCP_NODELAY:
result = m_no_delay;
break;
default:
dwarnln("getsockopt(IPPROTO_TCP, {})", option);
return BAN::Error::from_errno(ENOPROTOOPT);
}
break;
default:
dwarnln("getsockopt({}, {})", level, option);
return BAN::Error::from_errno(EINVAL);
} }
const size_t len = BAN::Math::min<size_t>(sizeof(result), *value_len); const size_t len = BAN::Math::min<size_t>(sizeof(result), *value_len);
@ -324,12 +349,50 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<void> TCPSocket::setsockopt_impl(int level, int option, const void* value, socklen_t value_len)
{
switch (level)
{
case SOL_SOCKET:
switch (option)
{
case SO_KEEPALIVE:
if (value_len != sizeof(int))
return BAN::Error::from_errno(EINVAL);
m_keep_alive = *static_cast<const int*>(value);
break;
default:
dwarnln("setsockopt(SOL_SOCKET, {})", option);
return BAN::Error::from_errno(ENOPROTOOPT);
}
break;
case IPPROTO_TCP:
switch (option)
{
case TCP_NODELAY:
if (value_len != sizeof(int))
return BAN::Error::from_errno(EINVAL);
m_no_delay = *static_cast<const int*>(value);
break;
default:
dwarnln("setsockopt(IPPROTO_TCP, {})", option);
return BAN::Error::from_errno(ENOPROTOOPT);
}
break;
default:
dwarnln("setsockopt({}, {})", level, option);
return BAN::Error::from_errno(EINVAL);
}
return {};
}
BAN::ErrorOr<long> TCPSocket::ioctl_impl(int request, void* argument) BAN::ErrorOr<long> TCPSocket::ioctl_impl(int request, void* argument)
{ {
switch (request) switch (request)
{ {
case FIONREAD: case FIONREAD:
*static_cast<int*>(argument) = m_recv_window.data_size; *static_cast<int*>(argument) = m_recv_window.buffer->size();
return 0; return 0;
} }
@ -342,14 +405,14 @@ namespace Kernel
return true; return true;
if (m_state == State::Listen) if (m_state == State::Listen)
return !m_pending_connections.empty(); return !m_pending_connections.empty();
return m_recv_window.data_size > 0; return !m_recv_window.buffer->empty();
} }
bool TCPSocket::can_write_impl() const bool TCPSocket::can_write_impl() const
{ {
if (m_state != State::Established) if (m_state != State::Established)
return false; return false;
return m_send_window.data_size < m_send_window.buffer->size(); return !m_send_window.buffer->full();
} }
bool TCPSocket::has_hungup_impl() const bool TCPSocket::has_hungup_impl() const
@ -422,7 +485,7 @@ namespace Kernel
if (header.options[i] == TCPOption::NOP) if (header.options[i] == TCPOption::NOP)
continue; continue;
if (header.options[i] == TCPOption::MaximumSeqmentSize) if (header.options[i] == TCPOption::MaximumSeqmentSize)
result.maximum_seqment_size = BAN::host_to_network_endian(*reinterpret_cast<const uint16_t*>(&header.options[i + 2])); result.maximum_seqment_size = BAN::network_endian_to_host(*reinterpret_cast<const uint16_t*>(&header.options[i + 2]));
if (header.options[i] == TCPOption::WindowScale) if (header.options[i] == TCPOption::WindowScale)
result.window_scale = header.options[i + 2]; result.window_scale = header.options[i + 2];
if (header.options[i + 1] == 0) if (header.options[i + 1] == 0)
@ -433,22 +496,28 @@ namespace Kernel
return result; return result;
} }
void TCPSocket::add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader pseudo_header) void TCPSocket::get_protocol_header(BAN::ByteSpan header_buffer, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader pseudo_header)
{ {
ASSERT(m_next_flags); ASSERT(m_next_flags);
ASSERT(m_mutex.locker() == Thread::current().tid()); ASSERT(m_mutex.locker() == Thread::current().tid());
ASSERT(header_buffer.size() == protocol_header_size());
auto& header = packet.as<TCPHeader>(); m_last_sent_window_size = m_should_send_zero_window ? 0 : m_recv_window.buffer->free();
memset(&header, 0, sizeof(TCPHeader));
memset(header.options, TCPOption::End, m_tcp_options_bytes); auto& header = header_buffer.as<TCPHeader>();
header = {
.src_port = bound_port(),
.dst_port = dst_port,
.seq_number = m_send_window.current_seq + m_send_window.has_ghost_byte,
.ack_number = m_recv_window.start_seq + m_recv_window.buffer->size() + m_recv_window.has_ghost_byte,
.data_offset = (sizeof(TCPHeader) + m_tcp_options_bytes) / sizeof(uint32_t),
.flags = m_next_flags,
.window_size = BAN::Math::min<size_t>(0xFFFF, m_last_sent_window_size >> m_recv_window.scale_shift),
.checksum = 0,
.urgent_pointer = 0,
};
memset(header.options, 0, m_tcp_options_bytes);
header.src_port = bound_port();
header.dst_port = dst_port;
header.seq_number = m_send_window.current_seq + m_send_window.has_ghost_byte;
header.ack_number = m_recv_window.start_seq + m_recv_window.data_size + m_recv_window.has_ghost_byte;
header.data_offset = (sizeof(TCPHeader) + m_tcp_options_bytes) / sizeof(uint32_t);
header.window_size = BAN::Math::min<size_t>(0xFFFF, m_recv_window.buffer->size() >> m_recv_window.scale_shift);
header.flags = m_next_flags;
if (header.flags & FIN) if (header.flags & FIN)
m_send_window.has_ghost_byte = true; m_send_window.has_ghost_byte = true;
m_next_flags = 0; m_next_flags = 0;
@ -467,24 +536,39 @@ namespace Kernel
if (m_connection_info->has_window_scale) if (m_connection_info->has_window_scale)
add_tcp_header_option<4, TCPOption::WindowScale>(header, m_recv_window.scale_shift); add_tcp_header_option<4, TCPOption::WindowScale>(header, m_recv_window.scale_shift);
header.window_size = BAN::Math::min<size_t>(0xFFFF, m_recv_window.buffer->size()); header.window_size = BAN::Math::min<size_t>(0xFFFF, m_recv_window.buffer->capacity());
m_send_window.mss = 1440;
m_send_window.start_seq++; m_send_window.start_seq++;
m_send_window.current_seq = m_send_window.start_seq; m_send_window.current_seq = m_send_window.start_seq;
} }
pseudo_header.extra = packet.size(); const BAN::ConstByteSpan buffers[] {
header.checksum = calculate_internet_checksum(packet, pseudo_header); BAN::ConstByteSpan::from(pseudo_header),
header_buffer,
payload,
};
header.checksum = calculate_internet_checksum({ buffers, sizeof(buffers) / sizeof(*buffers) });
dprintln_if(DEBUG_TCP, "sending {} {8b}", (uint8_t)m_state, header.flags); dprintln_if(DEBUG_TCP, "sending {} {8b}", (uint8_t)m_state, header.flags);
dprintln_if(DEBUG_TCP, " {}", (uint32_t)header.ack_number); dprintln_if(DEBUG_TCP, " ack {}", (uint32_t)header.ack_number);
dprintln_if(DEBUG_TCP, " {}", (uint32_t)header.seq_number); dprintln_if(DEBUG_TCP, " seq {}", (uint32_t)header.seq_number);
} }
void TCPSocket::receive_packet(BAN::ConstByteSpan buffer, const sockaddr* sender, socklen_t sender_len) void TCPSocket::receive_packet(BAN::ConstByteSpan buffer, const sockaddr* sender, socklen_t sender_len)
{ {
(void)sender_len; if (m_state == State::Listen)
{
auto socket =
[&]() -> BAN::RefPtr<TCPSocket> {
LockGuard _(m_mutex);
if (auto it = m_listen_children.find(ListenKey(sender, sender_len)); it != m_listen_children.end())
return it->value;
return {};
}();
if (socket)
return socket->receive_packet(buffer, sender, sender_len);
}
{ {
uint16_t checksum = 0; uint16_t checksum = 0;
@ -497,14 +581,17 @@ namespace Kernel
auto interface = interface_or_error.release_value(); auto interface = interface_or_error.release_value();
auto& addr_in = *reinterpret_cast<const sockaddr_in*>(sender); auto& addr_in = *reinterpret_cast<const sockaddr_in*>(sender);
checksum = calculate_internet_checksum(buffer, const PseudoHeader pseudo_header {
PseudoHeader {
.src_ipv4 = BAN::IPv4Address(addr_in.sin_addr.s_addr), .src_ipv4 = BAN::IPv4Address(addr_in.sin_addr.s_addr),
.dst_ipv4 = interface->get_ipv4_address(), .dst_ipv4 = interface->get_ipv4_address(),
.protocol = NetworkProtocol::TCP, .protocol = NetworkProtocol::TCP,
.extra = buffer.size() .length = buffer.size(),
} };
); const BAN::ConstByteSpan buffers[] {
BAN::ConstByteSpan::from(pseudo_header),
buffer
};
checksum = calculate_internet_checksum({ buffers, sizeof(buffers) / sizeof(*buffers) });
} }
else else
{ {
@ -524,11 +611,14 @@ namespace Kernel
const bool hungup_before = has_hungup_impl(); const bool hungup_before = has_hungup_impl();
auto& header = buffer.as<const TCPHeader>(); auto& header = buffer.as<const TCPHeader>();
dprintln_if(DEBUG_TCP, "receiving {} {8b}", (uint8_t)m_state, header.flags); dprintln_if(DEBUG_TCP, "receiving {} {8b}", (uint8_t)m_state, header.flags);
dprintln_if(DEBUG_TCP, " {}", (uint32_t)header.ack_number); dprintln_if(DEBUG_TCP, " ack {}", (uint32_t)header.ack_number);
dprintln_if(DEBUG_TCP, " {}", (uint32_t)header.seq_number); dprintln_if(DEBUG_TCP, " seq {}", (uint32_t)header.seq_number);
m_send_window.non_scaled_size = header.window_size; m_send_window.non_scaled_size = header.window_size;
if (m_send_window.scaled_size() == 0)
m_send_window.had_zero_window = true;
bool check_payload = false; bool check_payload = false;
switch (m_state) switch (m_state)
@ -547,8 +637,7 @@ namespace Kernel
} }
auto options = parse_tcp_options(header); auto options = parse_tcp_options(header);
if (options.maximum_seqment_size.has_value()) m_send_window.mss = options.maximum_seqment_size.value_or(s_default_mss);
m_send_window.mss = *options.maximum_seqment_size;
if (options.window_scale.has_value()) if (options.window_scale.has_value())
m_send_window.scale_shift = *options.window_scale; m_send_window.scale_shift = *options.window_scale;
else else
@ -573,44 +662,34 @@ namespace Kernel
m_has_connected = true; m_has_connected = true;
break; break;
case State::Listen: case State::Listen:
if (header.flags == SYN) if (header.flags != SYN)
{ dprintln_if(DEBUG_TCP, "Unexpected packet to listening socket");
if (m_pending_connections.size() == m_pending_connections.capacity()) else if (m_pending_connections.size() == m_pending_connections.capacity())
dprintln_if(DEBUG_TCP, "No storage to store pending connection"); dprintln_if(DEBUG_TCP, "No storage to store pending connection");
else else
{ {
const auto options = parse_tcp_options(header);
ConnectionInfo connection_info; ConnectionInfo connection_info;
memcpy(&connection_info.address, sender, sender_len); memcpy(&connection_info.address, sender, sender_len);
connection_info.address_len = sender_len; connection_info.address_len = sender_len;
connection_info.has_window_scale = parse_tcp_options(header).window_scale.has_value(); connection_info.has_window_scale = options.window_scale.has_value();
MUST(m_pending_connections.emplace( MUST(m_pending_connections.emplace(
connection_info, connection_info,
header.seq_number + 1 header.seq_number + 1,
options.maximum_seqment_size.value_or(s_default_mss),
options.window_scale.value_or(0)
)); ));
epoll_notify(EPOLLIN); epoll_notify(EPOLLIN);
m_thread_blocker.unblock(); m_thread_blocker.unblock();
} }
}
else
{
auto it = m_listen_children.find(ListenKey(sender, sender_len));
if (it == m_listen_children.end())
{
dprintln_if(DEBUG_TCP, "Unexpected packet to listening socket");
break;
}
auto socket = it->value;
m_mutex.unlock();
socket->receive_packet(buffer, sender, sender_len);
m_mutex.lock();
}
return; return;
case State::Established: case State::Established:
check_payload = true; check_payload = true;
if (!(header.flags & FIN)) if (!(header.flags & FIN))
break; break;
if (m_recv_window.start_seq + m_recv_window.data_size != header.seq_number) if (m_recv_window.start_seq + m_recv_window.buffer->size() != header.seq_number)
break; break;
m_next_flags = FIN | ACK; m_next_flags = FIN | ACK;
m_next_state = State::LastAck; m_next_state = State::LastAck;
@ -659,7 +738,9 @@ namespace Kernel
break; break;
} }
if (header.seq_number != m_recv_window.start_seq + m_recv_window.data_size + m_recv_window.has_ghost_byte) const uint32_t expected_seq = m_recv_window.start_seq + m_recv_window.buffer->size() + m_recv_window.has_ghost_byte;
if (header.seq_number > expected_seq)
dprintln_if(DEBUG_TCP, "Missing packets"); dprintln_if(DEBUG_TCP, "Missing packets");
else if (check_payload) else if (check_payload)
{ {
@ -670,28 +751,37 @@ namespace Kernel
m_send_window.current_ack = header.ack_number; m_send_window.current_ack = header.ack_number;
auto payload = buffer.slice(header.data_offset * sizeof(uint32_t)); auto payload = buffer.slice(header.data_offset * sizeof(uint32_t));
if (payload.size() > 0)
if (header.seq_number < expected_seq)
{ {
if (m_recv_window.data_size + payload.size() > m_recv_window.buffer->size()) const uint32_t already_received_bytes = expected_seq - header.seq_number;
dprintln_if(DEBUG_TCP, "Cannot fit received bytes to window, waiting for retransmission"); if (already_received_bytes <= payload.size())
payload = payload.slice(already_received_bytes);
else else
payload = {};
}
const bool can_receive_new_data = (payload.size() > 0 && !m_recv_window.buffer->full());
if (can_receive_new_data)
{ {
auto* buffer = reinterpret_cast<uint8_t*>(m_recv_window.buffer->vaddr()); const size_t nrecv = BAN::Math::min(payload.size(), m_recv_window.buffer->free());
memcpy(buffer + m_recv_window.data_size, payload.data(), payload.size()); m_recv_window.buffer->push(payload.slice(0, nrecv));
m_recv_window.data_size += payload.size();
epoll_notify(EPOLLIN); epoll_notify(EPOLLIN);
dprintln_if(DEBUG_TCP, "Received {} bytes", payload.size()); dprintln_if(DEBUG_TCP, "Received {} bytes", nrecv);
}
if (m_next_flags == 0) // make sure zero window is reported
if (m_last_sent_window_size > 0 && m_recv_window.buffer->full())
m_should_send_zero_window = true;
else if (can_receive_new_data)
{ {
m_next_flags = ACK; m_next_flags = ACK;
m_next_state = m_state; m_next_state = m_state;
} }
} }
}
}
if (!hungup_before && has_hungup_impl()) if (!hungup_before && has_hungup_impl())
epoll_notify(EPOLLHUP); epoll_notify(EPOLLHUP);
@ -793,21 +883,14 @@ namespace Kernel
continue; continue;
} }
if (m_send_window.data_size > 0 && m_send_window.current_ack - m_send_window.has_ghost_byte > m_send_window.start_seq) if (m_send_window.current_ack - m_send_window.has_ghost_byte > m_send_window.start_seq)
{ {
uint32_t acknowledged_bytes = m_send_window.current_ack - m_send_window.start_seq - m_send_window.has_ghost_byte; const uint32_t acknowledged_bytes = m_send_window.current_ack - m_send_window.start_seq - m_send_window.has_ghost_byte;
ASSERT(acknowledged_bytes <= m_send_window.data_size); ASSERT(acknowledged_bytes <= m_send_window.buffer->size());
m_send_window.data_size -= acknowledged_bytes;
m_send_window.start_seq += acknowledged_bytes; m_send_window.start_seq += acknowledged_bytes;
if (m_send_window.data_size > 0)
{
auto* send_buffer = reinterpret_cast<uint8_t*>(m_send_window.buffer->vaddr());
memmove(send_buffer, send_buffer + acknowledged_bytes, m_send_window.data_size);
}
m_send_window.sent_size -= acknowledged_bytes; m_send_window.sent_size -= acknowledged_bytes;
m_send_window.buffer->pop(acknowledged_bytes);
epoll_notify(EPOLLOUT); epoll_notify(EPOLLOUT);
@ -816,26 +899,32 @@ namespace Kernel
continue; continue;
} }
const bool should_retransmit = m_send_window.data_size > 0 && current_ms >= m_send_window.last_send_ms + retransmit_timeout_ms; const bool should_retransmit = m_send_window.had_zero_window || (m_send_window.sent_size > 0 && current_ms >= m_send_window.last_send_ms + retransmit_timeout_ms);
if (m_send_window.data_size > m_send_window.sent_size || should_retransmit) const bool can_send_new_data = (m_send_window.buffer->size() > m_send_window.sent_size && m_send_window.sent_size < m_send_window.scaled_size());
if (m_send_window.scaled_size() > 0 && (should_retransmit || can_send_new_data))
{ {
m_send_window.had_zero_window = false;
ASSERT(m_connection_info.has_value()); ASSERT(m_connection_info.has_value());
auto* target_address = reinterpret_cast<const sockaddr*>(&m_connection_info->address); auto* target_address = reinterpret_cast<const sockaddr*>(&m_connection_info->address);
auto target_address_len = m_connection_info->address_len; auto target_address_len = m_connection_info->address_len;
const uint32_t send_base = should_retransmit ? 0 : m_send_window.sent_size; const size_t send_offset = should_retransmit ? 0 : m_send_window.sent_size;
const uint32_t total_send = BAN::Math::min<uint32_t>(m_send_window.data_size - send_base, m_send_window.scaled_size()); const size_t total_send = BAN::Math::min<size_t>(
m_send_window.buffer->size() - send_offset,
m_send_window.scaled_size() - send_offset
);
m_send_window.current_seq = m_send_window.start_seq + m_send_window.sent_size; m_send_window.current_seq = m_send_window.start_seq + send_offset;
auto* send_buffer = reinterpret_cast<const uint8_t*>(m_send_window.buffer->vaddr() + send_base); for (size_t i = 0; i < total_send;)
for (uint32_t i = 0; i < total_send;)
{ {
const uint32_t to_send = BAN::Math::min(total_send - i, m_send_window.mss); const size_t to_send = BAN::Math::min<size_t>(total_send - i, m_send_window.mss);
auto message = BAN::ConstByteSpan(send_buffer + i, to_send); auto message = m_send_window.buffer->get_data().slice(send_offset + i, to_send);
m_next_flags = ACK; m_next_flags = ACK;
if (auto ret = m_network_layer.sendto(*this, message, target_address, target_address_len); ret.is_error()) if (auto ret = m_network_layer.sendto(*this, message, target_address, target_address_len); ret.is_error())
@ -846,9 +935,10 @@ namespace Kernel
dprintln_if(DEBUG_TCP, "Sent {} bytes", to_send); dprintln_if(DEBUG_TCP, "Sent {} bytes", to_send);
m_send_window.sent_size += to_send;
m_send_window.current_seq += to_send;
i += to_send; i += to_send;
m_send_window.current_seq += to_send;
if (send_offset + i > m_send_window.sent_size)
m_send_window.sent_size = send_offset + i;
} }
m_send_window.last_send_ms = current_ms; m_send_window.last_send_ms = current_ms;
@ -856,6 +946,30 @@ namespace Kernel
continue; continue;
} }
if (m_last_sent_window_size == 0)
m_should_send_zero_window = false;
if (m_should_send_zero_window || m_should_send_window_update)
{
ASSERT(m_connection_info.has_value());
auto* target_address = reinterpret_cast<const sockaddr*>(&m_connection_info->address);
auto target_address_len = m_connection_info->address_len;
m_next_flags = ACK;
if (auto ret = m_network_layer.sendto(*this, {}, target_address, target_address_len); ret.is_error())
dwarnln("{}", ret.error());
m_should_send_zero_window = false;
m_should_send_window_update = false;
if (m_last_sent_window_size == 0 && !m_recv_window.buffer->full())
{
m_next_flags = ACK;
if (auto ret = m_network_layer.sendto(*this, {}, target_address, target_address_len); ret.is_error())
dwarnln("{}", ret.error());
}
}
m_thread_blocker.unblock(); m_thread_blocker.unblock();
m_thread_blocker.block_with_wake_time_ms(current_ms + retransmit_timeout_ms, &m_mutex); m_thread_blocker.block_with_wake_time_ms(current_ms + retransmit_timeout_ms, &m_mutex);
} }

View File

@ -35,13 +35,26 @@ namespace Kernel
m_address_len = 0; m_address_len = 0;
} }
void UDPSocket::add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) void UDPSocket::get_protocol_header(BAN::ByteSpan header_buffer, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader pseudo_header)
{ {
auto& header = packet.as<UDPHeader>(); ASSERT(header_buffer.size() == protocol_header_size());
header.src_port = bound_port();
header.dst_port = dst_port; auto& header = header_buffer.as<UDPHeader>();
header.length = packet.size(); header = {
header.checksum = 0; .src_port = bound_port(),
.dst_port = dst_port,
.length = protocol_header_size() + payload.size(),
.checksum = 0,
};
const BAN::ConstByteSpan buffers[] {
BAN::ConstByteSpan::from(pseudo_header),
header_buffer,
payload,
};
header.checksum = calculate_internet_checksum({ buffers, sizeof(buffers) / sizeof(*buffers) });
if (header.checksum == 0)
header.checksum = 0xFFFF;
} }
void UDPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len) void UDPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len)
@ -212,10 +225,11 @@ namespace Kernel
BAN::ErrorOr<void> UDPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len) BAN::ErrorOr<void> UDPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len)
{ {
if (level != SOL_SOCKET)
return BAN::Error::from_errno(EINVAL);
int result; int result;
switch (level)
{
case SOL_SOCKET:
switch (option) switch (option)
{ {
case SO_ERROR: case SO_ERROR:
@ -228,7 +242,16 @@ namespace Kernel
result = m_packet_buffer->size(); result = m_packet_buffer->size();
break; break;
default: default:
return BAN::Error::from_errno(ENOTSUP); dwarnln("getsockopt(SOLSOCKET, {})", option);
return BAN::Error::from_errno(ENOPROTOOPT);
}
break;
case IPPROTO_UDP:
dwarnln("getsockopt(IPPROTO_UDP, {})", option);
return BAN::Error::from_errno(ENOPROTOOPT);
default:
dwarnln("getsockopt({}, {})", level, option);
return BAN::Error::from_errno(EINVAL);
} }
const size_t len = BAN::Math::min<size_t>(sizeof(result), *value_len); const size_t len = BAN::Math::min<size_t>(sizeof(result), *value_len);
@ -238,6 +261,27 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<void> UDPSocket::setsockopt_impl(int level, int option, const void* value, socklen_t value_len)
{
(void)value;
(void)value_len;
switch (level)
{
case SOL_SOCKET:
dwarnln("setsockopt(SOL_SOCKET, {})", option);
return BAN::Error::from_errno(ENOPROTOOPT);
case IPPROTO_UDP:
dwarnln("setsockopt(IPPROTO_UDP, {})", option);
return BAN::Error::from_errno(ENOPROTOOPT);
default:
dwarnln("setsockopt({}, {})", level, option);
return BAN::Error::from_errno(EINVAL);
}
return {};
}
BAN::ErrorOr<long> UDPSocket::ioctl_impl(int request, void* argument) BAN::ErrorOr<long> UDPSocket::ioctl_impl(int request, void* argument)
{ {
switch (request) switch (request)

View File

@ -707,7 +707,10 @@ namespace Kernel
BAN::ErrorOr<void> UnixDomainSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len) BAN::ErrorOr<void> UnixDomainSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len)
{ {
if (level != SOL_SOCKET) if (level != SOL_SOCKET)
{
dwarnln("getsockopt({}, {})", level, option);
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
}
int result; int result;
switch (option) switch (option)
@ -736,7 +739,10 @@ namespace Kernel
BAN::ErrorOr<void> UnixDomainSocket::setsockopt_impl(int level, int option, const void* value, socklen_t value_len) BAN::ErrorOr<void> UnixDomainSocket::setsockopt_impl(int level, int option, const void* value, socklen_t value_len)
{ {
if (level != SOL_SOCKET) if (level != SOL_SOCKET)
{
dwarnln("setsockopt({}, {})", level, option);
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
}
switch (option) switch (option)
{ {

View File

@ -5,6 +5,7 @@
#include <kernel/ELF.h> #include <kernel/ELF.h>
#include <kernel/Epoll.h> #include <kernel/Epoll.h>
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/EventFD.h>
#include <kernel/FS/ProcFS/FileSystem.h> #include <kernel/FS/ProcFS/FileSystem.h>
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/IDT.h> #include <kernel/IDT.h>
@ -28,6 +29,7 @@
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <sys/banan-os.h> #include <sys/banan-os.h>
#include <sys/eventfd.h>
#include <sys/futex.h> #include <sys/futex.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -379,7 +381,7 @@ namespace Kernel
const auto [master_addr, master_size] = master_tls; const auto [master_addr, master_size] = master_tls;
ASSERT(master_size % alignof(uthread) == 0); ASSERT(master_size % alignof(uthread) == 0);
const size_t tls_size = master_size + PAGE_SIZE; const size_t tls_size = master_size + sizeof(uthread);
auto region = TRY(MemoryBackedRegion::create( auto region = TRY(MemoryBackedRegion::create(
page_table, page_table,
@ -408,28 +410,26 @@ namespace Kernel
bytes_copied += to_copy; bytes_copied += to_copy;
} }
const uthread uthread { auto uthread = TRY(BAN::UniqPtr<struct uthread>::create());
*uthread = {
.self = reinterpret_cast<struct uthread*>(region->vaddr() + master_size), .self = reinterpret_cast<struct uthread*>(region->vaddr() + master_size),
.master_tls_addr = reinterpret_cast<void*>(master_addr), .master_tls_addr = reinterpret_cast<void*>(master_addr),
.master_tls_size = master_size, .master_tls_size = master_size,
.master_tls_module_count = 1,
.dynamic_tls = nullptr,
.cleanup_stack = nullptr, .cleanup_stack = nullptr,
.id = 0, .id = 0,
.errno_ = 0, .errno_ = 0,
.cancel_type = 0, .cancel_type = 0,
.cancel_state = 0, .cancel_state = 0,
.canceled = 0, .canceled = 0,
.dtv = { 0, region->vaddr() }
}; };
const uintptr_t dtv[2] { 1, region->vaddr() };
TRY(region->copy_data_to_region( TRY(region->copy_data_to_region(
master_size, master_size,
reinterpret_cast<const uint8_t*>(&uthread), reinterpret_cast<const uint8_t*>(uthread.ptr()),
sizeof(uthread) sizeof(struct uthread)
));
TRY(region->copy_data_to_region(
master_size + sizeof(uthread),
reinterpret_cast<const uint8_t*>(&dtv),
sizeof(dtv)
)); ));
TLSResult result; TLSResult result;
@ -1658,12 +1658,6 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_getsockopt(int socket, int level, int option_name, void* user_option_value, socklen_t* user_option_len) BAN::ErrorOr<long> Process::sys_getsockopt(int socket, int level, int option_name, void* user_option_value, socklen_t* user_option_len)
{ {
if (level != SOL_SOCKET)
{
dwarnln("{}: getsockopt level {}", name(), level);
return BAN::Error::from_errno(EINVAL);
}
socklen_t option_len; socklen_t option_len;
TRY(read_from_user(user_option_len, &option_len, sizeof(socklen_t))); TRY(read_from_user(user_option_len, &option_len, sizeof(socklen_t)));
@ -1685,12 +1679,6 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_setsockopt(int socket, int level, int option_name, const void* user_option_value, socklen_t option_len) BAN::ErrorOr<long> Process::sys_setsockopt(int socket, int level, int option_name, const void* user_option_value, socklen_t option_len)
{ {
if (level != SOL_SOCKET)
{
dwarnln("{}: setsockopt level {}", name(), level);
return BAN::Error::from_errno(EINVAL);
}
if (option_len < 0) if (option_len < 0)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
@ -2174,6 +2162,27 @@ namespace Kernel
return TRY(static_cast<Epoll*>(epoll_inode.ptr())->wait(BAN::Span<epoll_event>(events, maxevents), waketime_ns)); return TRY(static_cast<Epoll*>(epoll_inode.ptr())->wait(BAN::Span<epoll_event>(events, maxevents), waketime_ns));
} }
BAN::ErrorOr<long> Process::sys_eventfd(unsigned int initval, int flags)
{
if (flags & ~(EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE))
return BAN::Error::from_errno(EINVAL);
int oflags = 0;
if (flags & EFD_CLOEXEC)
oflags |= O_CLOEXEC;
if (flags & EFD_NONBLOCK)
oflags |= O_NONBLOCK;
const bool is_semaphore = !!(flags & EFD_SEMAPHORE);
return TRY(m_open_file_descriptors.open(
VirtualFileSystem::File {
TRY(EventFD::create(initval, is_semaphore)),
"<eventfd>"_sv
}, oflags
));
}
BAN::ErrorOr<long> Process::sys_pipe(int user_fildes[2]) BAN::ErrorOr<long> Process::sys_pipe(int user_fildes[2])
{ {
int fildes[2]; int fildes[2];
@ -2371,6 +2380,8 @@ namespace Kernel
TRY(read_string_from_user(user_path, path, PATH_MAX)); TRY(read_string_from_user(user_path, path, PATH_MAX));
auto new_cwd = TRY(find_file(AT_FDCWD, path, O_SEARCH)); auto new_cwd = TRY(find_file(AT_FDCWD, path, O_SEARCH));
if (!new_cwd.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
LockGuard _(m_process_lock); LockGuard _(m_process_lock);
m_working_directory = BAN::move(new_cwd); m_working_directory = BAN::move(new_cwd);
@ -2654,6 +2665,9 @@ namespace Kernel
for (size_t j = 0; j < new_regions.size(); j++) for (size_t j = 0; j < new_regions.size(); j++)
TRY(m_mapped_regions.insert(i + j + 1, BAN::move(new_regions[j]))); TRY(m_mapped_regions.insert(i + j + 1, BAN::move(new_regions[j])));
while (i + 1 < m_mapped_regions.size() && !m_mapped_regions[i + 1]->overlaps(vaddr, len))
i++;
continue; continue;
} }

View File

@ -73,7 +73,9 @@ namespace Kernel
: CharacterDevice(mode, uid, gid) : CharacterDevice(mode, uid, gid)
, m_termios(termios) , m_termios(termios)
, m_rdev(next_tty_rdev()) , m_rdev(next_tty_rdev())
{ } {
m_output.buffer = MUST(ByteRingBuffer::create(PAGE_SIZE));
}
BAN::RefPtr<TTY> TTY::current() BAN::RefPtr<TTY> TTY::current()
{ {
@ -204,7 +206,7 @@ namespace Kernel
} }
case FIONREAD: case FIONREAD:
{ {
*static_cast<int*>(argument) = m_output.flush ? m_output.bytes : 0; *static_cast<int*>(argument) = m_output.flush ? m_output.buffer->size() : 0;
return 0; return 0;
} }
case TIOCGWINSZ: case TIOCGWINSZ:
@ -232,14 +234,13 @@ namespace Kernel
return; return;
const char* ansi_c_str = LibInput::key_to_utf8_ansi(event.key, event.modifier); const char* ansi_c_str = LibInput::key_to_utf8_ansi(event.key, event.modifier);
if (ansi_c_str) if (ansi_c_str == nullptr)
{ return;
auto* ptr = reinterpret_cast<const uint8_t*>(ansi_c_str);
while (*ptr) while (*ansi_c_str)
handle_input_byte(*ptr++); handle_input_byte(*ansi_c_str++);
after_write(); after_write();
} }
}
void TTY::handle_input_byte(uint8_t ch) void TTY::handle_input_byte(uint8_t ch)
{ {
@ -287,7 +288,7 @@ namespace Kernel
if (ch == m_termios.c_cc[VKILL] && (m_termios.c_lflag & ECHOK)) if (ch == m_termios.c_cc[VKILL] && (m_termios.c_lflag & ECHOK))
{ {
while (m_output.bytes > 0 && m_output.buffer[m_output.bytes - 1] != '\n') while (!m_output.buffer->empty() && m_output.buffer->back() != '\n')
do_backspace(); do_backspace();
return; return;
} }
@ -307,12 +308,8 @@ namespace Kernel
// TODO: terminal suspension with VSTOP/VSTART // TODO: terminal suspension with VSTOP/VSTART
if (should_append) if (should_append && !m_output.buffer->full())
{ m_output.buffer->push({ &ch, 1 });
if (m_output.bytes >= m_output.buffer.size())
return;
m_output.buffer[m_output.bytes++] = ch;
}
if (should_append && (force_echo || (m_termios.c_lflag & ECHO))) if (should_append && (force_echo || (m_termios.c_lflag & ECHO)))
{ {
@ -350,29 +347,22 @@ namespace Kernel
void TTY::do_backspace() void TTY::do_backspace()
{ {
if (m_output.bytes > 0) if (m_output.buffer->empty())
{ return;
uint8_t last = m_output.buffer[m_output.bytes - 1];
// Multibyte UTF8 const bool is_caret_notation =
if ((last & 0xC0) == 0x80) (m_output.buffer->back() < 32) ||
(m_output.buffer->back() == 127);
// handle multibyte UTF8
while ((m_output.buffer->back() & 0xC0) == 0x80)
m_output.buffer->pop_back(1);
ASSERT(!m_output.buffer->empty());
m_output.buffer->pop_back(1);
if (is_caret_notation)
{ {
// NOTE: this should be valid UTF8 since keyboard input already 'validates' it
while ((m_output.buffer[m_output.bytes - 1] & 0xC0) == 0x80)
{
ASSERT(m_output.bytes > 0);
m_output.bytes--;
}
ASSERT(m_output.bytes > 0);
m_output.bytes--;
putchar('\b');
putchar(' ');
putchar('\b');
}
// Caret notation
else if (last < 32 || last == 127)
{
m_output.bytes--;
putchar('\b'); putchar('\b');
putchar('\b'); putchar('\b');
putchar(' '); putchar(' ');
@ -380,16 +370,13 @@ namespace Kernel
putchar('\b'); putchar('\b');
putchar('\b'); putchar('\b');
} }
// Ascii
else else
{ {
m_output.bytes--;
putchar('\b'); putchar('\b');
putchar(' '); putchar(' ');
putchar('\b'); putchar('\b');
} }
} }
}
bool TTY::putchar(uint8_t ch) bool TTY::putchar(uint8_t ch)
{ {
@ -411,7 +398,7 @@ namespace Kernel
while (!m_output.flush) while (!m_output.flush)
TRY(Thread::current().block_or_eintr_indefinite(m_output.thread_blocker, &m_mutex)); TRY(Thread::current().block_or_eintr_indefinite(m_output.thread_blocker, &m_mutex));
if (m_output.bytes == 0) if (m_output.buffer->empty())
{ {
if (master_has_closed()) if (master_has_closed())
return 0; return 0;
@ -419,19 +406,19 @@ namespace Kernel
return 0; return 0;
} }
const size_t max_to_copy = BAN::Math::min<size_t>(buffer.size(), m_output.bytes); auto data = m_output.buffer->get_data();
const size_t max_to_copy = BAN::Math::min<size_t>(buffer.size(), data.size());
size_t to_copy = max_to_copy; size_t to_copy = max_to_copy;
if (m_termios.c_lflag & ICANON) if (m_termios.c_lflag & ICANON)
for (to_copy = 1; to_copy < max_to_copy; to_copy++) for (to_copy = 1; to_copy < max_to_copy; to_copy++)
if (m_output.buffer[to_copy - 1] == NL) if (data[to_copy - 1] == NL)
break; break;
memcpy(buffer.data(), m_output.buffer.data(), to_copy); memcpy(buffer.data(), data.data(), to_copy);
m_output.buffer->pop(to_copy);
memmove(m_output.buffer.data(), m_output.buffer.data() + to_copy, m_output.bytes - to_copy); if (m_output.buffer->empty())
m_output.bytes -= to_copy;
if (m_output.bytes == 0)
m_output.flush = false; m_output.flush = false;
m_output.thread_blocker.unblock(); m_output.thread_blocker.unblock();

View File

@ -3,7 +3,7 @@
NAME='cairo' NAME='cairo'
VERSION='1.18.4' VERSION='1.18.4'
DOWNLOAD_URL="https://cairographics.org/releases/cairo-$VERSION.tar.xz#445ed8208a6e4823de1226a74ca319d3600e83f6369f99b14265006599c32ccb" DOWNLOAD_URL="https://cairographics.org/releases/cairo-$VERSION.tar.xz#445ed8208a6e4823de1226a74ca319d3600e83f6369f99b14265006599c32ccb"
DEPENDENCIES=('libpng' 'pixman' 'fontconfig' 'glib') DEPENDENCIES=('libpng' 'pixman' 'fontconfig' 'glib' 'libX11' 'libXrender' 'libXext')
CONFIGURE_OPTIONS=( CONFIGURE_OPTIONS=(
'-Dprefix=/usr' '-Dprefix=/usr'
'-Dtests=disabled' '-Dtests=disabled'

29
ports/dbus/build.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash ../install.sh
NAME='dbus'
VERSION='1.16.2'
DOWNLOAD_URL="https://dbus.freedesktop.org/releases/dbus/dbus-$VERSION.tar.xz#0ba2a1a4b16afe7bceb2c07e9ce99a8c2c3508e5dec290dbb643384bd6beb7e2"
DEPENDENCIES=('glib' 'expat')
CONFIGURE_OPTIONS=(
'-Dprefix=/usr'
'-Depoll=disabled' # linux only
'-Dintrusive_tests=false'
'-Dinstalled_tests=false'
'-Dmodular_tests=disabled'
)
configure() {
meson setup \
--reconfigure \
--cross-file "$MESON_CROSS_FILE" \
"${CONFIGURE_OPTIONS[@]}" \
build || exit 1
}
build() {
meson compile -C build || exit 1
}
install() {
meson install --destdir="$BANAN_SYSROOT" -C build || exit 1
}

View File

@ -0,0 +1,13 @@
diff -ruN dbus-1.16.2/tools/dbus-print-message.c dbus-1.16.2-banan_os/tools/dbus-print-message.c
--- dbus-1.16.2/tools/dbus-print-message.c 2025-02-27 18:29:06.000000000 +0200
+++ dbus-1.16.2-banan_os/tools/dbus-print-message.c 2026-02-21 23:23:51.987302740 +0200
@@ -31,7 +31,9 @@
#include <sys/un.h>
#include <unistd.h>
#include <netinet/in.h>
+#ifndef __banan_os__
#include <netinet/ip.h>
+#endif
#include <arpa/inet.h>
#endif

View File

@ -0,0 +1,48 @@
diff -ruN expat-2.7.1/configure expat-2.7.1-banan_os/configure
--- expat-2.7.1/configure 2025-03-27 21:46:37.000000000 +0200
+++ expat-2.7.1-banan_os/configure 2025-08-10 00:50:27.773898797 +0300
@@ -6679,6 +6679,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -12479,6 +12483,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"
@@ -18079,6 +18093,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

47
ports/fontconfig/build.sh Executable file
View File

@ -0,0 +1,47 @@
#!/bin/bash ../install.sh
NAME='fontconfig'
VERSION='2.17.1'
DOWNLOAD_URL="https://gitlab.freedesktop.org/fontconfig/fontconfig/-/archive/$VERSION/fontconfig-$VERSION.tar.gz#82e73b26adad651b236e5f5d4b3074daf8ff0910188808496326bd3449e5261d"
DEPENDENCIES=('harfbuzz' 'freetype' 'expat' 'libiconv')
CONFIGURE_OPTIONS=(
'-Dprefix=/usr'
'-Dtests=disabled'
'-Dnls=disabled'
)
configure() {
meson setup \
--reconfigure \
--cross-file "$MESON_CROSS_FILE" \
"${CONFIGURE_OPTIONS[@]}" \
build || exit 1
}
build() {
meson compile -C build || exit 1
}
install() {
meson install --destdir="$BANAN_SYSROOT" -C build || exit 1
}
post_install() {
pushd .. &>/dev/null
local font_name='dejavu-fonts-ttf-2.37'
if [ ! -f "$font_name.tar.bz2" ]; then
wget "http://sourceforge.net/projects/dejavu/files/dejavu/2.37/$font_name.tar.bz2" || exit 1
fi
if [ ! -d "$font_name" ]; then
tar xf "$font_name.tar.bz2" || exit 1
fi
mkdir -p "$BANAN_SYSROOT/usr/share/fonts/TTF" || exit 1
cp "$font_name/ttf/"* "$BANAN_SYSROOT/usr/share/fonts/TTF/" || exit 1
cp "$font_name/fontconfig/"* "$BANAN_SYSROOT/usr/share/fontconfig/conf.avail/" || exit 1
popd &>/dev/null
}

6
ports/fribidi/build.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash ../install.sh
NAME='fribidi'
VERSION='1.0.16'
DOWNLOAD_URL="https://github.com/fribidi/fribidi/releases/download/v$VERSION/fribidi-$VERSION.tar.xz#1b1cde5b235d40479e91be2f0e88a309e3214c8ab470ec8a2744d82a5a9ea05c"
CONFIG_SUB=('config.sub')

View File

@ -0,0 +1,20 @@
diff -ruN fribidi-1.0.16/configure fribidi-1.0.16-banan_os/configure
--- fribidi-1.0.16/configure 2024-09-25 21:04:21.000000000 +0300
+++ fribidi-1.0.16-banan_os/configure 2025-11-05 20:51:12.227775953 +0200
@@ -11536,6 +11536,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

27
ports/gdk-pixbuf/build.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/bash ../install.sh
NAME='gdk-pixbuf'
VERSION='2.44.4'
DOWNLOAD_URL="https://gitlab.gnome.org/GNOME/gdk-pixbuf/-/archive/$VERSION/gdk-pixbuf-$VERSION.tar.gz#6de2f77d992155b4121d20036e7e986dfe595a0e654381cdd0d7257f493c208a"
DEPENDENCIES=('glib' 'libpng' 'libjpeg' 'libtiff' 'shared-mime-info')
CONFIGURE_OPTIONS=(
'-Dprefix=/usr'
'-Dtests=false'
'-Dman=false'
)
configure() {
meson setup \
--reconfigure \
--cross-file "$MESON_CROSS_FILE" \
"${CONFIGURE_OPTIONS[@]}" \
build || exit 1
}
build() {
meson compile -C build || exit 1
}
install() {
meson install --destdir="$BANAN_SYSROOT" -C build || exit 1
}

View File

@ -1,13 +1,14 @@
#!/bin/bash ../install.sh #!/bin/bash ../install.sh
NAME='git' NAME='git'
VERSION='2.52.0' VERSION='2.53.0'
DOWNLOAD_URL="https://www.kernel.org/pub/software/scm/git/git-$VERSION.tar.xz#3cd8fee86f69a949cb610fee8cd9264e6873d07fa58411f6060b3d62729ed7c5" DOWNLOAD_URL="https://www.kernel.org/pub/software/scm/git/git-$VERSION.tar.xz#5818bd7d80b061bbbdfec8a433d609dc8818a05991f731ffc4a561e2ca18c653"
DEPENDENCIES=('zlib' 'openssl' 'curl') DEPENDENCIES=('zlib' 'openssl' 'curl' 'libiconv')
CONFIGURE_OPTIONS=( CONFIGURE_OPTIONS=(
'--with-curl' '--with-curl'
'--with-openssl' '--with-openssl'
ac_cv_fread_reads_directories=no ac_cv_fread_reads_directories=no
ac_cv_snprintf_returns_bogus=no ac_cv_iconv_omits_bom=no
ac_cv_lib_curl_curl_global_init=yes ac_cv_lib_curl_curl_global_init=yes
ac_cv_snprintf_returns_bogus=no
) )

30
ports/gtk3/build.sh Executable file
View File

@ -0,0 +1,30 @@
#!/bin/bash ../install.sh
NAME='gtk'
VERSION='3.24.49'
DOWNLOAD_URL="https://gitlab.gnome.org/GNOME/gtk/-/archive/$VERSION/gtk-$VERSION.tar.gz#a2958d82986c81794e953a3762335fa7c78948706d23cced421f7245ca544cbc"
DEPENDENCIES=('glib' 'gdk-pixbuf' 'pango' 'libatk' 'libepoxy' 'libXrandr')
CONFIGURE_OPTIONS=(
'-Dprefix=/usr'
'-Dtests=false'
'-Dexamples=false'
'-Dintrospection=false'
'-Dx11_backend=true'
'-Dwayland_backend=false'
)
configure() {
meson setup \
--reconfigure \
--cross-file "$MESON_CROSS_FILE" \
"${CONFIGURE_OPTIONS[@]}" \
build || exit 1
}
build() {
meson compile -C build || exit 1
}
install() {
meson install --destdir="$BANAN_SYSROOT" -C build || exit 1
}

45
ports/icu/build.sh Executable file
View File

@ -0,0 +1,45 @@
#!/bin/bash ../install.sh
NAME='icu'
VERSION='78.1'
DOWNLOAD_URL="https://github.com/unicode-org/icu/releases/download/release-$VERSION/icu4c-$VERSION-sources.tgz#6217f58ca39b23127605cfc6c7e0d3475fe4b0d63157011383d716cb41617886"
TAR_CONTENT='icu'
_DEPENDENCIES=('ca-certificates' 'openssl' 'zlib' 'zstd')
CONFIG_SUB=('source/config.sub')
CONFIGURE_OPTIONS=(
"--with-cross-build=$BANAN_PORT_DIR/icu/icu-$VERSION-$BANAN_ARCH/source/build-host"
'--disable-tests'
'--disable-samples'
)
pre_configure() {
unset CC CXX LD AS AR
mkdir -p source/build-host || exit 1
pushd source/build-host || exit 1
../configure --disable-tests --disable-samples || exit 1
make -j$(proc) || exit 1
popd >/dev/null || exit 1
pushd source >/dev/null || exit 1
}
post_configure() {
popd >/dev/null || exit 1
}
pre_build() {
pushd source >/dev/null || exit 1
}
post_build() {
popd >/dev/null || exit 1
}
pre_install() {
pushd source >/dev/null || exit 1
}
post_install() {
popd >/dev/null || exit 1
}

View File

@ -0,0 +1,95 @@
diff -ruN icu-78.1/source/config/mh-banan_os icu-78.1-banan_os/source/config/mh-banan_os
--- icu-78.1/source/config/mh-banan_os 1970-01-01 02:00:00.000000000 +0200
+++ icu-78.1-banan_os/source/config/mh-banan_os 2025-11-06 23:07:11.542495330 +0200
@@ -0,0 +1,80 @@
+## -*-makefile-*-
+## Copyright (C) 2016 and later: Unicode, Inc. and others.
+## License & terms of use: http://www.unicode.org/copyright.html
+## haiku-specific setup
+## Copyright (c) 2010-2012, International Business Machines Corporation and
+## others. All Rights Reserved.
+##
+
+## Commands to generate dependency files
+GEN_DEPS.c= $(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc= $(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -fPIC
+SHAREDLIBCXXFLAGS = -fPIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Additional flags when building libraries and with threads
+LIBCPPFLAGS =
+THREADSCPPFLAGS =
+
+#
+CPPFLAGS += -DU_CHARSET_IS_UTF8=1
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=
+LD_RPATH_PRE = -Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+
+## Shared object suffix
+SO = so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+ $(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+ $(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+ $(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+ $(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+ @echo "generating dependency information for $<"
+ @$(SHELL) -ec '$(GEN_DEPS.c) $< \
+ | sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+ [ -s $@ ] || rm -f $@'
+
+%.d: $(srcdir)/%.cpp
+ @echo "generating dependency information for $<"
+ @$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+ | sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+ [ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+ $(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+ $(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+## Bind internal references
+
+# LDflags that pkgdata will use
+BIR_LDFLAGS= -Wl,-Bsymbolic
+
+# Dependencies [i.e. map files] for the final library
+BIR_DEPS=
+
+# Use LIBRARY_PATH instead of LD_LIBRARY_PATH
+LDLIBRARYPATH_ENVVAR= LIBRARY_PATH
+
+## End haiku-specific setup
diff -ruN icu-78.1/source/configure icu-78.1-banan_os/source/configure
--- icu-78.1/source/configure 2025-10-30 19:37:19.000000000 +0200
+++ icu-78.1-banan_os/source/configure 2025-11-06 23:06:17.308923216 +0200
@@ -5829,6 +5829,7 @@
*-apple-darwin*) icu_cv_host_frag=mh-darwin ;;
*-*-beos) icu_cv_host_frag=mh-beos ;;
*-*-haiku) icu_cv_host_frag=mh-haiku ;;
+*-*-banan_os) icu_cv_host_frag=mh-banan_os ;;
*-*-irix*) icu_cv_host_frag=mh-irix ;;
*-dec-osf*) icu_cv_host_frag=mh-alpha-osf ;;
*-*-nto*) icu_cv_host_frag=mh-qnx ;;

View File

@ -0,0 +1,11 @@
--- icu/source/common/unicode/ptypes.h 2025-10-30 19:37:19.000000000 +0200
+++ icu-78.1-x86_64/source/common/unicode/ptypes.h 2025-11-06 23:12:15.984514832 +0200
@@ -56,7 +56,7 @@
// implementations (looking at you, Apple, spring 2024) actually do this, so
// ICU4C must detect and deal with that.
#if !defined(__cplusplus) && !defined(U_IN_DOXYGEN)
-# if U_HAVE_CHAR16_T
+# if ! U_HAVE_CHAR16_T
# include <uchar.h>
# else
typedef uint16_t char16_t;

11
ports/libICE/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libICE'
VERSION='1.1.2'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libICE-$VERSION.tar.xz#974e4ed414225eb3c716985df9709f4da8d22a67a2890066bc6dfc89ad298625"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('xorgproto' 'xtrans')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libICE-1.1.2/configure libICE-1.1.2-banan_os/configure
--- libICE-1.1.2/configure 2024-12-13 23:40:33.000000000 +0200
+++ libICE-1.1.2-banan_os/configure 2025-11-16 23:38:24.456211241 +0200
@@ -6464,6 +6464,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11969,6 +11973,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libSM/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libSM'
VERSION='1.2.6'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libSM-$VERSION.tar.xz#be7c0abdb15cbfd29ac62573c1c82e877f9d4047ad15321e7ea97d1e43d835be"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libICE')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libSM-1.2.6/configure libSM-1.2.6-banan_os/configure
--- libSM-1.2.6/configure 2025-03-09 03:46:18.000000000 +0200
+++ libSM-1.2.6-banan_os/configure 2025-11-16 23:36:16.733929290 +0200
@@ -6262,6 +6262,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11797,6 +11801,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libX11/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libX11'
VERSION='1.8.12'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libX11-$VERSION.tar.xz#fa026f9bb0124f4d6c808f9aef4057aad65e7b35d8ff43951cef0abe06bb9a9a"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('xorgproto' 'xtrans' 'libxcb')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libX11-1.8.12/configure libX11-1.8.12-banan_os/configure
--- libX11-1.8.12/configure 2025-03-09 01:53:09.000000000 +0200
+++ libX11-1.8.12-banan_os/configure 2025-11-13 20:07:46.592619585 +0200
@@ -6633,6 +6633,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -12138,6 +12142,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXau/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXau'
VERSION='1.0.12'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXau-$VERSION.tar.xz#74d0e4dfa3d39ad8939e99bda37f5967aba528211076828464d2777d477fc0fb"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('xorgproto')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXau-1.0.12/configure libXau-1.0.12-banan_os/configure
--- libXau-1.0.12/configure 2024-12-14 03:33:02.000000000 +0200
+++ libXau-1.0.12-banan_os/configure 2025-11-13 20:00:35.574268731 +0200
@@ -6224,6 +6224,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -12060,6 +12064,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXaw/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXaw'
VERSION='1.0.16'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXaw-$VERSION.tar.xz#731d572b54c708f81e197a6afa8016918e2e06dfd3025e066ca642a5b8c39c8f"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11' 'libXext' 'libXt' 'libXmu' 'libXpm')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXaw-1.0.16/configure libXaw-1.0.16-banan_os/configure
--- libXaw-1.0.16/configure 2024-03-10 19:39:54.000000000 +0200
+++ libXaw-1.0.16-banan_os/configure 2025-11-16 23:51:15.704550082 +0200
@@ -5977,6 +5977,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11343,6 +11347,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXdmcp/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXdmcp'
VERSION='1.1.5'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXdmcp-$VERSION.tar.xz#d8a5222828c3adab70adf69a5583f1d32eb5ece04304f7f8392b6a353aa2228c"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('xorgproto')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXdmcp-1.1.5/configure libXdmcp-1.1.5-banan_os/configure
--- libXdmcp-1.1.5/configure 2024-03-02 23:37:19.000000000 +0200
+++ libXdmcp-1.1.5-banan_os/configure 2025-11-13 21:49:06.142805910 +0200
@@ -6247,6 +6247,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11960,6 +11964,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

12
ports/libXext/build.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash ../install.sh
NAME='libXext'
VERSION='1.3.6'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXext-$VERSION.tar.xz#edb59fa23994e405fdc5b400afdf5820ae6160b94f35e3dc3da4457a16e89753"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
'--disable-malloc0returnsnull'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXext-1.3.6/configure libXext-1.3.6-banan_os/configure
--- libXext-1.3.6/configure 2024-02-04 23:42:50.000000000 +0200
+++ libXext-1.3.6-banan_os/configure 2025-11-16 23:30:16.532954111 +0200
@@ -6282,6 +6282,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11663,6 +11667,16 @@
;;
esac
;;
+
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
beos*)
library_names_spec='$libname$shared_ext'

11
ports/libXfixes/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXfixes'
VERSION='6.0.2'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXfixes-$VERSION.tar.xz#39f115d72d9c5f8111e4684164d3d68cc1fd21f9b27ff2401b08fddfc0f409ba"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXfixes-6.0.2/configure libXfixes-6.0.2-banan_os/configure
--- libXfixes-6.0.2/configure 2025-09-02 02:25:56.000000000 +0300
+++ libXfixes-6.0.2-banan_os/configure 2025-11-16 23:59:00.284383978 +0200
@@ -6157,6 +6157,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11692,6 +11696,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXfont2/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXfont2'
VERSION='2.0.7'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXfont2-$VERSION.tar.xz#8b7b82fdeba48769b69433e8e3fbb984a5f6bf368b0d5f47abeec49de3e58efb"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('freetype' 'xorgproto' 'xtrans' 'libfontenc')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXfont2-2.0.7/configure libXfont2-2.0.7-banan_os/configure
--- libXfont2-2.0.7/configure 2024-08-02 02:38:54.000000000 +0300
+++ libXfont2-2.0.7-banan_os/configure 2025-11-13 20:21:21.333718050 +0200
@@ -6558,6 +6558,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11940,6 +11944,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXft/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXft'
VERSION='2.3.9'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXft-$VERSION.tar.xz#60a25b78945ed6932635b3bb1899a517d31df7456e69867ffba27f89ff3976f5"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libXrender' 'libX11' 'freetype' 'fontconfig')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXft-2.3.9/configure libXft-2.3.9-banan_os/configure
--- libXft-2.3.9/configure 2025-04-20 18:10:46.000000000 +0300
+++ libXft-2.3.9-banan_os/configure 2025-11-17 01:42:42.971908492 +0200
@@ -5873,6 +5873,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11239,6 +11243,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

12
ports/libXi/build.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash ../install.sh
NAME='libXi'
VERSION='1.8.2'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXi-$VERSION.tar.xz#d0e0555e53d6e2114eabfa44226ba162d2708501a25e18d99cfb35c094c6c104"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11' 'libXext' 'libXfixes')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
'--disable-malloc0returnsnull'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXi-1.8.2/configure libXi-1.8.2-banan_os/configure
--- libXi-1.8.2/configure 2024-09-05 04:19:46.000000000 +0300
+++ libXi-1.8.2-banan_os/configure 2025-11-16 23:54:14.061298859 +0200
@@ -6020,6 +6020,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11377,6 +11381,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXmu/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXmu'
VERSION='1.2.1'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXmu-$VERSION.tar.xz#fcb27793248a39e5fcc5b9c4aec40cc0734b3ca76aac3d7d1c264e7f7e14e8b2"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libXt' 'libXext' 'libX11')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXmu-1.2.1/configure libXmu-1.2.1-banan_os/configure
--- libXmu-1.2.1/configure 2024-04-16 23:02:25.000000000 +0300
+++ libXmu-1.2.1-banan_os/configure 2025-11-16 23:42:28.961754856 +0200
@@ -6165,6 +6165,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11492,6 +11496,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXpm/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXpm'
VERSION='3.5.17'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXpm-$VERSION.tar.xz#64b31f81019e7d388c822b0b28af8d51c4622b83f1f0cb6fa3fc95e271226e43"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXpm-3.5.17/configure libXpm-3.5.17-banan_os/configure
--- libXpm-3.5.17/configure 2023-10-03 19:12:11.000000000 +0300
+++ libXpm-3.5.17-banan_os/configure 2025-11-16 23:46:08.171880860 +0200
@@ -5897,6 +5897,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11254,6 +11258,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXrandr/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXrandr'
VERSION='1.5.5'
DOWNLOAD_URL="https://xorg.freedesktop.org/archive/individual/lib/libXrandr-$VERSION.tar.xz#72b922c2e765434e9e9f0960148070bd4504b288263e2868a4ccce1b7cf2767a"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11' 'libXext' 'libXrender')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXrandr-1.5.5/configure libXrandr-1.5.5-banan_os/configure
--- libXrandr-1.5.5/configure 2026-01-26 02:25:38.000000000 +0200
+++ libXrandr-1.5.5-banan_os/configure 2026-02-21 23:34:03.906187857 +0200
@@ -6162,6 +6162,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11697,6 +11701,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXrender/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXrender'
VERSION='0.9.12'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXrender-$VERSION.tar.xz#b832128da48b39c8d608224481743403ad1691bf4e554e4be9c174df171d1b97"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXrender-0.9.12/configure libXrender-0.9.12-banan_os/configure
--- libXrender-0.9.12/configure 2024-12-13 23:07:57.000000000 +0200
+++ libXrender-0.9.12-banan_os/configure 2025-11-17 00:04:56.995318198 +0200
@@ -6035,6 +6035,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11570,6 +11574,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXt/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXt'
VERSION='1.3.1'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXt-$VERSION.tar.xz#e0a774b33324f4d4c05b199ea45050f87206586d81655f8bef4dba434d931288"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libSM' 'libICE' 'libX11')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXt-1.3.1/configure libXt-1.3.1-banan_os/configure
--- libXt-1.3.1/configure 2024-11-17 06:44:13.000000000 +0200
+++ libXt-1.3.1-banan_os/configure 2025-11-16 23:33:28.525874895 +0200
@@ -6313,6 +6313,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11695,6 +11699,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXtst/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXtst'
VERSION='1.2.5'
DOWNLOAD_URL="https://xorg.freedesktop.org/archive/individual/lib/libXtst-$VERSION.tar.xz#b50d4c25b97009a744706c1039c598f4d8e64910c9fde381994e1cae235d9242"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11' 'libXext' 'libXi')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libXtst-1.2.5/configure libXtst-1.2.5-banan_os/configure
--- libXtst-1.2.5/configure 2024-08-02 03:27:45.000000000 +0300
+++ libXtst-1.2.5-banan_os/configure 2026-02-21 23:29:27.999396388 +0200
@@ -6194,6 +6194,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11606,6 +11610,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

26
ports/libatk/build.sh Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash ../install.sh
NAME='libatk'
VERSION='2.56.6'
DOWNLOAD_URL="https://gitlab.gnome.org/GNOME/at-spi2-core/-/archive/$VERSION/at-spi2-core-$VERSION.tar.gz#49b1a640d50a95389a31672a0a077f0c20e8e222322cbd0228d3fa597686819d"
TAR_CONTENT="at-spi2-core-$VERSION"
DEPENDENCIES=('glib' 'dbus' 'libxml2' 'libX11' 'libXtst')
CONFIGURE_OPTIONS=(
'-Dprefix=/usr'
)
configure() {
meson setup \
--reconfigure \
--cross-file "$MESON_CROSS_FILE" \
"${CONFIGURE_OPTIONS[@]}" \
build || exit 1
}
build() {
meson compile -C build || exit 1
}
install() {
meson install --destdir="$BANAN_SYSROOT" -C build || exit 1
}

27
ports/libepoxy/build.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/bash ../install.sh
NAME='libepoxy'
VERSION='1.5.10'
DOWNLOAD_URL="https://download.gnome.org/sources/libepoxy/1.5/libepoxy-$VERSION.tar.xz#072cda4b59dd098bba8c2363a6247299db1fa89411dc221c8b81b8ee8192e623"
DEPENDENCIES=('mesa' 'libX11')
CONFIGURE_OPTIONS=(
'-Dprefix=/usr'
'-Dtests=false'
'-Degl=no'
)
configure() {
meson setup \
--reconfigure \
--cross-file "$MESON_CROSS_FILE" \
"${CONFIGURE_OPTIONS[@]}" \
build || exit 1
}
build() {
meson compile -C build || exit 1
}
install() {
meson install --destdir="$BANAN_SYSROOT" -C build || exit 1
}

View File

@ -0,0 +1,23 @@
--- libepoxy-1.5.10/src/dispatch_common.c 2022-02-17 14:56:12.000000000 +0200
+++ libepoxy-1.5.10-banan_os/src/dispatch_common.c 2025-11-11 18:35:23.194563757 +0200
@@ -164,7 +164,9 @@
#include <windows.h>
#else
#include <dlfcn.h>
+#ifndef __banan_os__
#include <err.h>
+#endif
#include <pthread.h>
#endif
#include <string.h>
@@ -306,8 +308,10 @@
pthread_mutex_lock(&api.mutex);
if (!*handle) {
int flags = RTLD_LAZY | RTLD_LOCAL;
+#ifdef RTLD_NOLOAD
if (!load)
flags |= RTLD_NOLOAD;
+#endif
*handle = dlopen(lib_name, flags);
if (!*handle) {

11
ports/libfontenc/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libfontenc'
VERSION='1.1.8'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libfontenc-$VERSION.tar.xz#7b02c3d405236e0d86806b1de9d6868fe60c313628b38350b032914aa4fd14c6"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('zlib' 'xorgproto')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libfontenc-1.1.8/configure libfontenc-1.1.8-banan_os/configure
--- libfontenc-1.1.8/configure 2024-03-02 20:32:14.000000000 +0200
+++ libfontenc-1.1.8-banan_os/configure 2025-11-13 20:25:22.782104114 +0200
@@ -6145,6 +6145,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11527,6 +11531,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

View File

@ -0,0 +1,5 @@
#!/bin/bash ../install.sh
NAME='libpthread-stubs'
VERSION='0.5'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libpthread-stubs-$VERSION.tar.xz#59da566decceba7c2a7970a4a03b48d9905f1262ff94410a649224e33d2442bc"

11
ports/libxcb/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libxcb'
VERSION='1.17.0'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libxcb-$VERSION.tar.xz#599ebf9996710fea71622e6e184f3a8ad5b43d0e5fa8c4e407123c88a59a6d55"
CONFIG_SUB=('config.sub' 'build-aux/config.sub')
DEPENDENCIES=('xcb-proto' 'libXau' 'libXdmcp' 'libpthread-stubs')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libxcb-1.17.0/configure libxcb-1.17.0-banan_os/configure
--- libxcb-1.17.0/configure 2024-04-15 18:09:34.000000000 +0300
+++ libxcb-1.17.0-banan_os/configure 2025-11-13 19:58:33.829610129 +0200
@@ -6886,6 +6886,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -12538,6 +12542,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libxkbfile/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libxkbfile'
VERSION='1.1.3'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libxkbfile-$VERSION.tar.xz#a9b63eea997abb9ee6a8b4fbb515831c841f471af845a09de443b28003874bec"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11' 'xkeyboard-config')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@ -0,0 +1,31 @@
diff -ruN libxkbfile-1.1.3/configure libxkbfile-1.1.3-banan_os/configure
--- libxkbfile-1.1.3/configure 2024-02-05 00:14:27.000000000 +0200
+++ libxkbfile-1.1.3-banan_os/configure 2025-11-13 20:14:55.314294954 +0200
@@ -5944,6 +5944,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11356,6 +11360,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

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