Compare commits

...

100 Commits

Author SHA1 Message Date
Bananymous 9d0990e5e8 Kernel: Implement /proc/<n>/fd 2025-11-24 00:19:51 +02:00
Bananymous 3207f5d61f Kernel: Fix possible page fault on file lookup 2025-11-23 19:49:07 +02:00
Bananymous c72b351bba LibC: Implement glob{,free} 2025-11-23 05:33:44 +02:00
Bananymous 1f9b296ae7 cp: Add -r/--recursive flag 2025-11-23 02:25:05 +02:00
Bananymous e3e2e7b4df userspace: Implement mv utility 2025-11-23 02:24:52 +02:00
Bananymous 4ec8f4a4bf Kernel/LibC: Implement rename{,at} 2025-11-22 23:55:10 +02:00
Bananymous 05d59a05df Kernel: Remove obsolete kprint
This hasn't been in use in 3 years :)
2025-11-22 06:21:50 +02:00
Bananymous 11ccbe6506 ports/SDL2: Add clipboard support 2025-11-22 01:24:06 +02:00
Bananymous 673711a246 ports/mesa: Require llvm
I dont't really even want to suppot softpipe as that is so slow
2025-11-22 00:40:14 +02:00
Bananymous fff5139d80 Kernel: Add /proc/<n>/cwd
Also update /proc/<n>/* permissions to match what linux does :D
2025-11-18 05:40:36 +02:00
Bananymous 812e70c626 ports: Add zsh port 2025-11-18 05:40:36 +02:00
Bananymous db7ffcf9d5 Kernel/Terminal: Add support for bracketed paste mode
This gets rid of annoying warnings when running some programs like bash
2025-11-18 05:40:36 +02:00
Bananymous 8f6cb9c057 Terminal: Add selection and clipboard support
text can now be copied with ctrl+shift+c and pasted with ctrl+shift+v
2025-11-18 05:40:36 +02:00
Bananymous 291f298d19 userspace: Implement LibClipboard and ClipboardServer
programs can now connect to the clipboard server using libclipboard and
get and set the clipboard of the current user
2025-11-18 05:40:36 +02:00
Bananymous d60f12d3b8 Kernel: Add support for SCM_CREDENTIALS and fix recvmsg
recvmsg was broken when receiving into more than a single iovec
2025-11-18 05:40:36 +02:00
Bananymous b8a2573bb4 userspace: Implement ImageViewer utility
This supports viewing images and doing basic zooming and panning
2025-11-17 20:58:12 +02:00
Bananymous 7ce8e610f5 stat: Fix handling of symlinks 2025-11-17 05:26:07 +02:00
Bananymous 839b9c8f07 Kernel: Check parent's sticky bit in unlink 2025-11-17 05:26:07 +02:00
Bananymous db20801521 Shell: Add exec builtin 2025-11-17 05:26:07 +02:00
Bananymous 160a9278c9 LibC: Fix RTLD_* definitions 2025-11-17 05:26:07 +02:00
Bananymous ee507de154 LibC: Implement posix regex
This is an almost complete implementation, it does not support
alternations or collating elements and it is restricted to the ASCII
character set
2025-11-17 05:26:07 +02:00
Bananymous dc0fa49de2 ports/tuxracer: Add sound support and fix compiling 2025-11-17 05:26:07 +02:00
Bananymous b678541427 ports: Add SDL_mixer port 2025-11-17 05:26:07 +02:00
Bananymous 6c4cd0d8cb ports: Add libmikmod port 2025-11-17 05:26:07 +02:00
Bananymous c096d3cd42 ports/sdl12-compat: Define that banan-os has alloca.h 2025-11-17 05:26:07 +02:00
Bananymous dcdab4df21 ports/sdl12-compat: Remove unnecessary patch
This is not needed as our SDL2 library is in the expected form
2025-11-17 05:26:07 +02:00
Bananymous 9803209ba1 WindowServer: Make clients nonblock
Also dont allow freezed windows to "steal" focus and lock up the window
server :D
2025-11-17 05:26:07 +02:00
Bananymous f166cb09ec Kernel: Fail xHCI initialization if page size != 4096
Also zero out scratchapd buffers as the spec says
2025-11-17 05:26:07 +02:00
Bananymous 2dd8b76289 BuildSystem: Automatically delete libtool files
Half of the ports had a manual post_install step to delete libtool files
this is now done automatically and there is no need for it!

Libtool files have to be deleted as libtool doesn't work while
cross-compiling (at least out of the box)
2025-11-17 05:26:07 +02:00
Bananymous 2bf7c67767 LibC: Add backtrace signal handlers for SIG{FPE,ILL,BUS,SEGV}
This allows programs to dump better backtraces on crashes compared to
what kernel can as libc can resolve symbols and libraries' dynamic bases
2025-11-17 05:26:07 +02:00
Bananymous dd636ffcb2 Kernel: Add support for SA_SIGINFO 2025-11-17 05:26:07 +02:00
Bananymous a44c45ff9e LibC: Cleanup signal.h
Make sa_handler and sa_sigaction be part of an union

Add definitions of SIGIO TRAP_BRKPT TRAP_TRACE
2025-11-17 05:26:07 +02:00
Bananymous dc2a455395 Kernel: Optimize processes' memory management
Memory regions are now stored in a sorted array. This allows O(nlogn)
lookup for address validation instead of the old linear lookup.

Now inserting new regions is also O(nlogn) instead of the old constant
time, but lookups are **much** more frequent
2025-11-17 05:26:07 +02:00
Bananymous c700d9f714 Kernel: Implement connect for UDP socket 2025-11-17 05:26:07 +02:00
Bananymous 59cfc339b0 Kernel: Ignore MSG_NOSIGNAL and invalid flags 2025-11-17 05:26:07 +02:00
Bananymous e06c07ca89 ports: Update binutils 2.44->2.45
Now we don't have to keep patches for both versions around :D
2025-11-17 05:26:07 +02:00
Bananymous 6facd54a7e LibC: Add ru_maxrss to struct rusage
This is not required by posix but some ports use it
2025-11-17 05:26:07 +02:00
Bananymous 6f8d850726 BuildSystem: Cleanup port building script
All dependencies are now installed only ones. If a port depends on for
examle zlib and one of its other dependencies depends on zlib, zlib will
now get installe only once.

Accept .tgz archives as the main download file
2025-11-17 05:26:07 +02:00
Bananymous f3beee9874 Kernel: Cleanup userspace pointer validation 2025-11-17 02:33:00 +02:00
Bananymous 35e063bdaf Kernel: Dump r8-r15 on x86_64 exceptions 2025-11-17 02:33:00 +02:00
Bananymous 09175d1799 Kernel: Fix 32 bit target
Rewrite some assembly and add some required casts
2025-11-17 02:33:00 +02:00
Bananymous 46f9a9053f DynamicLoader: Use canonical path for the main executable 2025-11-13 04:20:53 +02:00
Bananymous bb86520094 Kernel: Set message flags in UDP and TCP recvmsg 2025-11-13 04:20:53 +02:00
Bananymous c1e2c660bf LibC: Define caddr_t
This is used by some ports
2025-11-13 04:20:53 +02:00
Bananymous 89c0ff1a9d Kernel/LibC: Replace SYS_{GET,SET}_TLS with SYS_{SET,GET}_{FS,GS}BASE
This allows userspace to use both registers
2025-11-13 04:20:53 +02:00
Bananymous 7a68ce7e94 DynamicLoader: Fix testing for possible base address
Replace MAP_FIXED with MAP_FIXED_NOREPLACE and only attempt to map
program headers with PT_LOAD
2025-11-13 04:20:53 +02:00
Bananymous 9537922acc Kernel: Implement proper memory region splitting
Memory regions are now splitted when they get munmapped, mprotected, or
mmapped with MAP_FIXED. This is used by couple of ports, and without
this we were just leaking up memory or straight up crashing programs.
2025-11-13 04:20:53 +02:00
Bananymous a39aa73e21 Kernel: Allow munmap on non-page aligned address 2025-11-12 00:06:36 +02:00
Bananymous f1d12c330e Kernel/LibC: Implement MMAP_FIXED_NOREPLACE
This is a handy thing from linux

Also fix MMAP_FIXED validation and error reporting
2025-11-12 00:06:36 +02:00
Bananymous 82c8eeb4be ports/openssh: Update to 10.2p1 and enable fd passing 2025-11-12 00:06:36 +02:00
Bananymous 3a951f4830 LibC: Define IN_LOOPBACKNET
some ports expect this to exist
2025-11-12 00:06:36 +02:00
Bananymous 998ea25fb9 LibC: Add netinet/in_systm.h compatibility header 2025-11-12 00:06:36 +02:00
Bananymous 7b580b8f56 Kernel: Implement fd passing with SCM_RIGTHS 2025-11-12 00:06:36 +02:00
Bananymous 641ccfdd47 LibC: Add BSD compatibility defines S_I{READ,WRITE,EXEC}
These just map to S_I{R,W,X}USR respectively
2025-11-10 01:40:33 +02:00
Bananymous 4288f70d04 LibC: Make poll and epoll macros match with each other
This was an assertion in one of my ports and I couldn't be bothered to
write a patch for it :D
2025-11-10 01:40:33 +02:00
Bananymous 95fda5dfb7 LibC: Add definitions for IPPROTO_ICMPV6 and IP_TOS 2025-11-10 01:40:33 +02:00
Bananymous 1903c5e0c6 Kernel: Use user given address hint in mmap if possible 2025-11-10 01:40:33 +02:00
Bananymous 362501a097 LibC: Make x86_64 crt0 PIE compatible
Instead of pushing addresses of functions directly, use rip relative
addressing
2025-11-10 01:40:33 +02:00
Bananymous 72982e3c2b Kernel/LibC: Take fcntl extra field as uintptr_t
This allows passing pointers to fcntl
2025-11-10 01:40:33 +02:00
Bananymous 04d24bce70 Kernel/LibC: Implement {recv,send}msg as syscalls
This also removes the now old recvfrom and sendto syscalls. These are
now implemented as wrappers around recvmsg and sendmsg.

Also replace unnecessary spinlocks from unix socket with mutexes
2025-11-10 01:40:33 +02:00
Bananymous 2f38306c6b LibC: Implement simple posix_spawn{,p}
This does not support file_actions or attributes
2025-11-10 01:40:33 +02:00
Bananymous 4b36e5197d LibC: Implement execvpe
This is not part of posix but it seems handy
2025-11-09 16:12:29 +02:00
Bananymous b755cf3e42 LibC: Add sockatmark stub 2025-11-07 14:57:00 +02:00
Bananymous 3acad7c911 LibC: Add ifreq.ifr_{flags,mtu} and fix defines
compatibility defines for ifr_{netmask,gwaddr,hwaddr} were wrong
2025-11-07 14:55:30 +02:00
Bananymous f3319016c4 LibC: Implement if_{,free}nameindex 2025-11-07 14:54:53 +02:00
Bananymous 4e14f7d483 LibC: Implement {,l,ll}{abs,div} 2025-11-06 23:20:35 +02:00
Bananymous 979059c804 Kernel: Implement ext2 symlinks with >= 60 byte target 2025-11-06 17:21:36 +02:00
Bananymous bdf4423512 ports/freetype: Add missing dependencies 2025-11-04 23:06:13 +02:00
Bananymous c6ef4b5840 userspace: Implement kill utility 2025-11-04 19:19:46 +02:00
Bananymous acd792d8b4 userspace: Implement pwd utility 2025-11-04 18:46:13 +02:00
Bananymous fc730679ed userspace: Implement uname utility 2025-11-04 18:45:20 +02:00
Bananymous 00e5749e20 ports: Add SuperTux port 2025-11-02 22:47:02 +02:00
Bananymous 7b4d349574 ports: Add glm port 2025-11-02 22:47:02 +02:00
Bananymous dc0cccfb6c ports: Add physfs port 2025-11-02 22:47:02 +02:00
Bananymous fdc1daefb6 ports: Add libvorbis port 2025-11-02 22:47:02 +02:00
Bananymous c9159b81c8 ports: Add libogg port 2025-11-02 22:47:02 +02:00
Bananymous 9233049356 ports: Add openal-soft port 2025-11-02 22:47:02 +02:00
Bananymous bd9015e474 ports: Add libsndfile port 2025-11-02 22:47:02 +02:00
Bananymous 3a79540d2d ports: Add SDL2_image port 2025-11-02 22:47:02 +02:00
Bananymous 9e500dc387 ports: Add boost port 2025-11-02 22:47:02 +02:00
Bananymous e05a735589 DynamicLoader: Honour STB_LOCAL binding 2025-11-02 22:47:02 +02:00
Bananymous 0be18c4a53 DynamicLoader: Make everything thread safe
This is kinda dumb implementation, but it works. We grap a global lock
on functions :)
2025-11-02 22:47:02 +02:00
Bananymous e258fde25a LibC: Implement unnamed semaphores 2025-11-02 21:11:16 +02:00
Bananymous 7367672570 Kernel: Default initialize flock as unlocked
This caused unlocked flock's to hang on lock
2025-11-02 21:10:13 +02:00
Bananymous b822d42889 LibC: Define ESHUTDOWN
This is not used but some ports expect it to exist
2025-11-02 21:09:48 +02:00
Bananymous 10084ff1bb LibC: Define FIONBIO
This doesn't do anything but some ports expect it to exist
2025-11-02 21:07:26 +02:00
Bananymous c3c69ac727 LibC: Update _POSIX_* definitions and extern environ
environ is externed by other operating systems so some ports expect it
to be there
2025-10-30 16:49:12 +02:00
Bananymous 0cfda6f6a7 LibC: Add posix_fadvise as no-op 2025-10-30 16:34:03 +02:00
Bananymous dc51ce9e92 LibC: Implement readdir_r and fix memory leak 2025-10-30 16:33:17 +02:00
Bananymous aa0de2b00e LibC: Fix stack_t::ss_sp type from void** -> void* 2025-10-30 15:43:25 +02:00
Bananymous 5f61581e1d Kernel: Show QR code with panic logs on kernel panic
This makes debugging on real hardware easier!
2025-10-28 05:50:19 +02:00
Bananymous f519cb2cc0 Kernel: Expose boot framebuffer device 2025-10-28 05:50:19 +02:00
Bananymous 37aef630d2 BAN: Fix Array and Vector span constness 2025-10-28 05:50:19 +02:00
Bananymous d93fcff5db userspace: Add LibQR
This library can be used to generate QR codes
2025-10-28 05:50:19 +02:00
Bananymous 4952a82af5 LibImage: Use LibDEFLATE instead of builtin DEFLATE decompressor 2025-10-28 05:50:19 +02:00
Bananymous fecda6a034 userspace: Add LibDEFLATE
This can be used to compress and decompress DEFLATE data either in raw
or zlib format
2025-10-28 05:50:19 +02:00
Bananymous 9f0addbd8b BAN: Implement simple priority queue
This is just a wrapper around BAN::Vector and heap functions
2025-10-26 00:32:00 +03:00
Bananymous 7f8ea6b8e0 BAN: Move heap functions to Heap.h
This also adds push_heap and pop_heap, similar to what C++ standard
library provides
2025-10-26 00:31:06 +03:00
Bananymous 9d3ea6fed7 BAN: Use new it_value_type_t in sorting functions 2025-10-26 00:30:51 +03:00
Bananymous 703b3eda56 BAN: Add it_value_type_t
This is a template that resolves into T for pointers to T and T::value_type otherwise. It allows using the underlaying type of an iterator or pointer for range based algorithms
2025-10-26 00:22:35 +03:00
203 changed files with 8918 additions and 2118 deletions

View File

@ -35,7 +35,7 @@ namespace BAN
constexpr T& front();
Span<T> span() { return Span(m_data, size()); }
const Span<T> span() const { return Span(m_data, size()); }
Span<const T> span() const { return Span(m_data, size()); }
constexpr size_type size() const;

90
BAN/include/BAN/Heap.h Normal file
View File

@ -0,0 +1,90 @@
#pragma once
#include <BAN/Iteration.h>
#include <BAN/Swap.h>
#include <BAN/Traits.h>
#include <cstddef>
namespace BAN
{
namespace detail
{
template<typename It, typename Comp>
void heapify_up(It begin, size_t index, Comp comp)
{
size_t parent = (index - 1) / 2;
while (parent < index)
{
if (comp(*(begin + index), *(begin + parent)))
break;
swap(*(begin + parent), *(begin + index));
index = parent;
parent = (index - 1) / 2;
}
}
template<typename It, typename Comp>
void heapify_down(It begin, size_t index, size_t len, Comp comp)
{
for (;;)
{
const size_t lchild = 2 * index + 1;
const size_t rchild = 2 * index + 2;
size_t child = 0;
if (lchild < len && !comp(*(begin + lchild), *(begin + index)))
{
if (rchild < len && !comp(*(begin + rchild), *(begin + lchild)))
child = rchild;
else
child = lchild;
}
else if (rchild < len && !comp(*(begin + rchild), *(begin + index)))
child = rchild;
else
break;
swap(*(begin + child), *(begin + index));
index = child;
}
}
}
template<typename It, typename Comp = less<it_value_type_t<It>>>
void make_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
if (len <= 1)
return;
size_t index = (len - 2) / 2;
while (index < len)
detail::heapify_down(begin, index--, len, comp);
}
template<typename It, typename Comp = less<it_value_type_t<It>>>
void push_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
detail::heapify_up(begin, len - 1, comp);
}
template<typename It, typename Comp = less<it_value_type_t<It>>>
void pop_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
swap(*begin, *(begin + len - 1));
detail::heapify_down(begin, 0, len - 1, comp);
}
template<typename It, typename Comp = less<it_value_type_t<It>>>
void sort_heap(It begin, It end, Comp comp = {})
{
while (begin != end)
pop_heap(begin, end--, comp);
}
}

View File

@ -0,0 +1,64 @@
#pragma once
#include "BAN/Errors.h"
#include <BAN/Vector.h>
#include <BAN/Heap.h>
namespace BAN
{
template<typename T, typename Comp = less<T>>
class PriorityQueue
{
public:
PriorityQueue() = default;
PriorityQueue(Comp comp)
: m_comp(comp)
{ }
ErrorOr<void> push(const T& value)
{
TRY(m_data.push_back(value));
push_heap(m_data.begin(), m_data.end());
return {};
}
ErrorOr<void> push(T&& value)
{
TRY(m_data.push_back(move(value)));
push_heap(m_data.begin(), m_data.end());
return {};
}
template<typename... Args>
ErrorOr<void> emplace(Args&&... args) requires is_constructible_v<T, Args...>
{
TRY(m_data.emplace_back(forward<Args>(args)...));
push_heap(m_data.begin(), m_data.end());
return {};
}
void pop()
{
pop_heap(m_data.begin(), m_data.end());
m_data.pop_back();
}
BAN::ErrorOr<void> reserve(Vector<T>::size_type size)
{
return m_data.reserve(size);
}
T& top() { return m_data.front(); }
const T& top() const { return m_data.front(); }
bool empty() const { return m_data.empty(); }
Vector<T>::size_type size() const { return m_data.size(); }
Vector<T>::size_type capacity() const { return m_data.capacity(); }
private:
Comp m_comp;
Vector<T> m_data;
};
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <BAN/Heap.h>
#include <BAN/Math.h>
#include <BAN/Swap.h>
#include <BAN/Traits.h>
@ -8,7 +9,7 @@
namespace BAN::sort
{
template<typename It, typename Comp = less<typename It::value_type>>
template<typename It, typename Comp = less<it_value_type_t<It>>>
void exchange_sort(It begin, It end, Comp comp = {})
{
for (It lhs = begin; lhs != end; ++lhs)
@ -42,7 +43,7 @@ namespace BAN::sort
}
template<typename It, typename Comp = less<typename It::value_type>>
template<typename It, typename Comp = less<it_value_type_t<It>>>
void quick_sort(It begin, It end, Comp comp = {})
{
if (distance(begin, end) <= 1)
@ -52,14 +53,14 @@ namespace BAN::sort
quick_sort(++mid, end, comp);
}
template<typename It, typename Comp = less<typename It::value_type>>
template<typename It, typename Comp = less<it_value_type_t<It>>>
void insertion_sort(It begin, It end, Comp comp = {})
{
if (distance(begin, end) <= 1)
return;
for (It it1 = next(begin, 1); it1 != end; ++it1)
{
typename It::value_type x = move(*it1);
auto x = move(*it1);
It it2 = it1;
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
*it2 = move(*prev(it2, 1));
@ -67,83 +68,7 @@ namespace BAN::sort
}
}
namespace detail
{
template<typename It, typename Comp>
void push_heap(It begin, size_t hole_index, size_t top_index, typename It::value_type value, Comp comp)
{
size_t parent = (hole_index - 1) / 2;
while (hole_index > top_index && comp(*next(begin, parent), value))
{
*next(begin, hole_index) = move(*next(begin, parent));
hole_index = parent;
parent = (hole_index - 1) / 2;
}
*next(begin, hole_index) = move(value);
}
template<typename It, typename Comp>
void adjust_heap(It begin, size_t hole_index, size_t len, typename It::value_type value, Comp comp)
{
const size_t top_index = hole_index;
size_t child = hole_index;
while (child < (len - 1) / 2)
{
child = 2 * (child + 1);
if (comp(*next(begin, child), *next(begin, child - 1)))
child--;
*next(begin, hole_index) = move(*next(begin, child));
hole_index = child;
}
if (len % 2 == 0 && child == (len - 2) / 2)
{
child = 2 * (child + 1);
*next(begin, hole_index) = move(*next(begin, child - 1));
hole_index = child - 1;
}
push_heap(begin, hole_index, top_index, move(value), comp);
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void make_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
if (len <= 1)
return;
size_t parent = (len - 2) / 2;
while (true)
{
detail::adjust_heap(begin, parent, len, move(*next(begin, parent)), comp);
if (parent == 0)
break;
parent--;
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void sort_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
if (len <= 1)
return;
size_t last = len;
while (last > 1)
{
last--;
typename It::value_type x = move(*next(begin, last));
*next(begin, last) = move(*begin);
detail::adjust_heap(begin, 0, last, move(x), comp);
}
}
template<typename It, typename Comp = less<typename It::value_type>>
template<typename It, typename Comp = less<it_value_type_t<It>>>
void heap_sort(It begin, It end, Comp comp = {})
{
make_heap(begin, end, comp);
@ -167,7 +92,7 @@ namespace BAN::sort
}
template<typename It, typename Comp = less<typename It::value_type>>
template<typename It, typename Comp = less<it_value_type_t<It>>>
void intro_sort(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
@ -190,10 +115,10 @@ namespace BAN::sort
}
template<typename It, size_t radix = 256>
requires is_unsigned_v<typename It::value_type> && (radix > 0 && (radix & (radix - 1)) == 0)
requires is_unsigned_v<it_value_type_t<It>> && (radix > 0 && (radix & (radix - 1)) == 0)
BAN::ErrorOr<void> radix_sort(It begin, It end)
{
using value_type = typename It::value_type;
using value_type = it_value_type_t<It>;
const size_t len = distance(begin, end);
if (len <= 1)
@ -231,7 +156,7 @@ namespace BAN::sort
return {};
}
template<typename It, typename Comp = less<typename It::value_type>>
template<typename It, typename Comp = less<it_value_type_t<It>>>
void sort(It begin, It end, Comp comp = {})
{
return intro_sort(begin, end, comp);

View File

@ -139,6 +139,10 @@ namespace BAN
template<typename T> using make_signed_t = typename make_signed<T>::type;
#undef __BAN_TRAITS_MAKE_SIGNED_CV
template<typename T> struct it_value_type { using value_type = T::value_type; };
template<typename T> struct it_value_type<T*> { using value_type = T; };
template<typename T> using it_value_type_t = typename it_value_type<T>::value_type;
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };

View File

@ -56,7 +56,7 @@ namespace BAN
bool contains(const T&) const;
Span<T> span() { return Span(m_data, m_size); }
const Span<T> span() const { return Span(m_data, m_size); }
Span<const T> span() const { return Span(m_data, m_size); }
const T& operator[](size_type) const;
T& operator[](size_type);

View File

@ -165,6 +165,12 @@ set(KLIBC_SOURCES
../userspace/libraries/LibC/arch/${BANAN_ARCH}/string.S
)
set(LIBDEFLATE_SOURCE
../userspace/libraries/LibDEFLATE/Compressor.cpp
../userspace/libraries/LibDEFLATE/Decompressor.cpp
../userspace/libraries/LibDEFLATE/HuffmanTree.cpp
)
set(LIBFONT_SOURCES
../userspace/libraries/LibFont/Font.cpp
../userspace/libraries/LibFont/PSF.cpp
@ -175,18 +181,25 @@ set(LIBINPUT_SOURCE
../userspace/libraries/LibInput/KeyEvent.cpp
)
set(LIBQR_SOURCE
../userspace/libraries/LibQR/QRCode.cpp
)
set(KERNEL_SOURCES
${KERNEL_SOURCES}
${BAN_SOURCES}
${KLIBC_SOURCES}
${LIBDEFLATE_SOURCE}
${LIBFONT_SOURCES}
${LIBINPUT_SOURCE}
${LIBQR_SOURCE}
)
add_executable(kernel ${KERNEL_SOURCES})
target_compile_definitions(kernel PRIVATE __is_kernel)
target_compile_definitions(kernel PRIVATE __arch=${BANAN_ARCH})
target_compile_definitions(kernel PRIVATE LIBDEFLATE_AVOID_STACK=1)
target_compile_options(kernel PRIVATE
-O2 -g
@ -240,9 +253,11 @@ add_custom_command(
banan_include_headers(kernel ban)
banan_include_headers(kernel libc)
banan_include_headers(kernel libfont)
banan_include_headers(kernel libdeflate)
banan_include_headers(kernel libelf)
banan_include_headers(kernel libfont)
banan_include_headers(kernel libinput)
banan_include_headers(kernel libqr)
banan_install_headers(kernel)
set_target_properties(kernel PROPERTIES OUTPUT_NAME banan-os.kernel)

View File

@ -2,15 +2,41 @@
// stack contains
// return address
// return stack
// return rflags
// siginfo_t
// signal number
// signal handler
.global signal_trampoline
signal_trampoline:
pusha
pushl %esi // gregs
pushl %edi
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
pushl %ebp
movl 40(%esp), %edi
movl 36(%esp), %eax
movl 76(%esp), %eax // return sp
addl $4, %eax // return address
movl 80(%esp), %ebx // return ip
pushl %eax;
pushl %ebx
// FIXME: populate these
xorl %eax, %eax
pushl %eax // stack
pushl %eax
pushl %eax
pushl %eax // sigset
pushl %eax
pushl %eax // link
movl %esp, %edx // ucontext
leal 68(%esp), %esi // siginfo
movl 64(%esp), %edi // signal number
movl 60(%esp), %eax // handlers
// align stack to 16 bytes
movl %esp, %ebp
@ -19,7 +45,9 @@ signal_trampoline:
subl $512, %esp
fxsave (%esp)
subl $12, %esp
subl $4, %esp
pushl %edx
pushl %esi
pushl %edi
call *%eax
addl $16, %esp
@ -29,9 +57,21 @@ signal_trampoline:
// restore stack
movl %ebp, %esp
popa
addl $32, %esp
addl $8, %esp
// restore registers
popl %ebp
popl %eax
popl %ebx
popl %ecx
popl %edx
popl %edi
popl %esi
// skip handler, number, siginfo_t
addl $44, %esp
// restore flags
popf
movl (%esp), %esp

View File

@ -1,12 +1,6 @@
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
.global asm_syscall_handler
asm_syscall_handler:
# save segment registers
pushw %ds
pushw %es
pushw %fs
pushw %gs
# save general purpose registers
pushl %ebx
pushl %ecx
@ -18,13 +12,12 @@ asm_syscall_handler:
# align stack
movl %esp, %ebp
subl $15, %esp
andl $0xFFFFFFF0, %esp
andl $-16, %esp
# push arguments
subl $4, %esp
pushl %ebp
addl $32, (%esp)
addl $24, (%esp)
pushl %edi
pushl %esi
pushl %edx
@ -44,6 +37,15 @@ asm_syscall_handler:
movl %ebp, %esp
# restore userspace segments
movw $(0x20 | 3), %bx
movw %bx, %ds
movw %bx, %es
movw $(0x30 | 3), %bx
movw %bx, %fs
movw $(0x38 | 3), %bx
movw %bx, %gs
# restore general purpose registers
popl %ebp
popl %esi
@ -52,12 +54,6 @@ asm_syscall_handler:
popl %ecx
popl %ebx
# restore segment registers
popw %gs
popw %fs
popw %es
popw %ds
iret
.global sys_fork_trampoline

View File

@ -31,8 +31,6 @@ start_kernel_thread:
subl $12, %esp
pushl %edi
call *%esi
addl $16, %esp
.global start_userspace_thread
start_userspace_thread:
@ -41,15 +39,12 @@ start_userspace_thread:
call get_thread_start_sp
movl %eax, %esp
# ds, es = user data
movw $(0x20 | 3), %bx
movw %bx, %ds
movw %bx, %es
# gs = thread local
movw $(0x30 | 3), %bx
movw %bx, %gs
# fs = 0
xorw %bx, %bx
movw %bx, %fs
movw $(0x38 | 3), %bx
movw %bx, %gs
iret

View File

@ -1,12 +1,7 @@
.macro push_userspace
pushw %gs
pushw %fs
pushw %es
pushw %ds
pushal
.endm
.macro maybe_load_kernel_segments, n
cmpb $0x08, \n(%esp)
je 1f
.macro load_kernel_segments
movw $0x10, %ax
movw %ax, %ds
movw %ax, %es
@ -14,19 +9,26 @@
movw $0x28, %ax
movw %ax, %gs
1:
.endm
.macro pop_userspace
popal
popw %ds
popw %es
popw %fs
popw %gs
.macro maybe_load_userspace_segments, n
cmpb $0x08, \n(%esp)
je 1f
movw $(0x20 | 3), %bx
movw %bx, %ds
movw %bx, %es
movw $(0x30 | 3), %bx
movw %bx, %fs
movw $(0x38 | 3), %bx
movw %bx, %gs
1:
.endm
isr_stub:
push_userspace
load_kernel_segments
pushal
maybe_load_kernel_segments 44
cld
movl %cr0, %eax; pushl %eax
@ -34,33 +36,39 @@ isr_stub:
movl %cr3, %eax; pushl %eax
movl %cr4, %eax; pushl %eax
movl %esp, %eax // register ptr
leal 64(%esp), %ebx // interrupt stack ptr
movl 60(%esp), %ecx // error code
movl 56(%esp), %edx // isr number
movl 48(%esp), %edi // isr number
movl 52(%esp), %esi // error code
leal 56(%esp), %edx // interrupt stack ptr
movl %esp, %ecx // register ptr
# stack frame for stack trace
leal 56(%esp), %eax
pushl (%eax)
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
pushl %eax
pushl %ebx
pushl %ecx
pushl %edx
pushl %esi
pushl %edi
call cpp_isr_handler
movl %ebp, %esp
addl $16, %esp
addl $24, %esp
pop_userspace
maybe_load_userspace_segments 44
popal
addl $8, %esp
iret
irq_stub:
push_userspace
load_kernel_segments
pushal
maybe_load_kernel_segments 44
cld
movl 40(%esp), %edi # interrupt number
movl 32(%esp), %edi # interrupt number
movl %esp, %ebp
andl $-16, %esp
@ -71,7 +79,8 @@ irq_stub:
movl %ebp, %esp
pop_userspace
maybe_load_userspace_segments 44
popal
addl $8, %esp
iret
@ -99,8 +108,8 @@ asm_yield_handler:
.global asm_ipi_handler
asm_ipi_handler:
push_userspace
load_kernel_segments
pushal
maybe_load_kernel_segments 36
cld
movl %esp, %ebp
@ -110,13 +119,14 @@ asm_ipi_handler:
movl %ebp, %esp
pop_userspace
maybe_load_userspace_segments 36
popal
iret
.global asm_timer_handler
asm_timer_handler:
push_userspace
load_kernel_segments
pushal
maybe_load_kernel_segments 36
cld
movl %esp, %ebp
@ -126,7 +136,8 @@ asm_timer_handler:
movl %ebp, %esp
pop_userspace
maybe_load_userspace_segments 36
popal
iret
.macro isr n

View File

@ -2,29 +2,48 @@
// stack contains
// return address
// return stack
// return rflags
// siginfo_t
// signal number
// signal handler
.global signal_trampoline
signal_trampoline:
pushq %rax
pushq %rbx
pushq %rcx
pushq %rdx
pushq %rbp
pushq %rdi
pushq %rsi
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r15 // gregs
pushq %r14
pushq %r15
pushq %r13
pushq %r12
pushq %r11
pushq %r10
pushq %r9
pushq %r8
pushq %rsi
pushq %rdi
pushq %rdx
pushq %rcx
pushq %rbx
pushq %rax
pushq %rbp
movq 128(%rsp), %rdi
movq 120(%rsp), %rax
movq 200(%rsp), %rax // return sp
addq $(128 + 8), %rax // red-zone and return address
movq 208(%rsp), %rbx // return ip
pushq %rax;
pushq %rbx
// FIXME: populate these
xorq %rax, %rax
pushq %rax // stack
pushq %rax
pushq %rax
pushq %rax // sigset
pushq %rax // link
movq %rsp, %rdx // ucontext
leaq 192(%rsp), %rsi // siginfo
movq 184(%rsp), %rdi // signal number
movq 176(%rsp), %rax // handler
// align stack to 16 bytes
movq %rsp, %rbp
@ -40,26 +59,32 @@ signal_trampoline:
// restore stack
movq %rbp, %rsp
popq %r15
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rsi
popq %rdi
popq %rbp
popq %rdx
popq %rcx
popq %rbx
popq %rax
addq $56, %rsp
addq $16, %rsp
// restore registers
popq %rbp
popq %rax
popq %rbx
popq %rcx
popq %rdx
popq %rdi
popq %rsi
popq %r8
popq %r9
popq %r10
popq %r11
popq %r12
popq %r13
popq %r14
popq %r15
// skip handler, number, siginfo_t
addq $72, %rsp
// restore flags
popfq
movq (%rsp), %rsp
// return over red-zone
// return over red-zone and siginfo_t
ret $128

View File

@ -2,6 +2,7 @@
// System V ABI: RDI, RSI, RDX, RCX, R8, R9
.global asm_syscall_handler
asm_syscall_handler:
swapgs
pushq %rbx
pushq %rcx
pushq %rdx
@ -42,9 +43,9 @@ asm_syscall_handler:
popq %rdx
popq %rcx
popq %rbx
swapgs
iretq
.global sys_fork_trampoline
sys_fork_trampoline:
pushq %rbx

View File

@ -32,4 +32,6 @@ start_userspace_thread:
call get_thread_start_sp
movq %rax, %rsp
swapgs
iretq

View File

@ -1,4 +1,12 @@
.macro pushaq
.macro swapgs_if_necessary, n
cmpb $0x08, \n(%rsp)
je 1f
swapgs
1:
.endm
.macro pushaq, n
swapgs_if_necessary \n
pushq %rax
pushq %rcx
pushq %rdx
@ -16,7 +24,7 @@
pushq %r15
.endm
.macro popaq
.macro popaq, n
popq %r15
popq %r14
popq %r13
@ -32,10 +40,11 @@
popq %rdx
popq %rcx
popq %rax
swapgs_if_necessary \n
.endm
isr_stub:
pushaq
pushaq 24
cld
movq %cr0, %rax; pushq %rax
movq %cr2, %rax; pushq %rax
@ -49,43 +58,43 @@ isr_stub:
call cpp_isr_handler
addq $32, %rsp
popaq
popaq 24
addq $16, %rsp
iretq
irq_stub:
pushaq
pushaq 24
cld
movq 120(%rsp), %rdi # irq number
call cpp_irq_handler
popaq
popaq 24
addq $16, %rsp
iretq
.global asm_yield_handler
asm_yield_handler:
pushaq
pushaq 8
cld
leaq 120(%rsp), %rdi # interrupt stack ptr
movq %rsp, %rsi # interrupt register ptr
call cpp_yield_handler
popaq
popaq 8
iretq
.global asm_ipi_handler
asm_ipi_handler:
pushaq
pushaq 8
cld
call cpp_ipi_handler
popaq
popaq 8
iretq
.global asm_timer_handler
asm_timer_handler:
pushaq
pushaq 8
cld
call cpp_timer_handler
popaq
popaq 8
iretq
.macro isr n

View File

@ -74,6 +74,8 @@
namespace Debug
{
void dump_stack_trace();
void dump_qr_code();
void putchar(char);
void print_prefix(const char*, int);

View File

@ -10,6 +10,7 @@ namespace Kernel
{
public:
static BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> create_from_boot_framebuffer();
static BAN::RefPtr<FramebufferDevice> boot_framebuffer();
~FramebufferDevice();
uint32_t width() const { return m_width; }

View File

@ -37,6 +37,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override;
virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) override;
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
@ -64,6 +65,7 @@ namespace Kernel
BAN::ErrorOr<BAN::Optional<uint32_t>> fs_block_of_data_block_index(uint32_t data_block_index);
BAN::ErrorOr<void> link_inode_to_directory(Ext2Inode&, BAN::StringView name);
BAN::ErrorOr<void> remove_inode_from_directory(BAN::StringView name, bool cleanup_directory);
BAN::ErrorOr<bool> is_directory_empty();
BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth);

View File

@ -97,6 +97,7 @@ namespace Kernel
BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t);
BAN::ErrorOr<void> create_directory(BAN::StringView, mode_t, uid_t, gid_t);
BAN::ErrorOr<void> link_inode(BAN::StringView, BAN::RefPtr<Inode>);
BAN::ErrorOr<void> rename_inode(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView);
BAN::ErrorOr<void> unlink(BAN::StringView);
// Link API
@ -108,8 +109,8 @@ namespace Kernel
BAN::ErrorOr<void> bind(const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<void> connect(const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<void> listen(int backlog);
BAN::ErrorOr<size_t> sendto(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<size_t> recvfrom(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<size_t> sendmsg(const msghdr& message, int flags);
BAN::ErrorOr<size_t> recvmsg(msghdr& message, int flags);
BAN::ErrorOr<void> getsockname(sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<void> getpeername(sockaddr* address, socklen_t* address_len);
@ -144,6 +145,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
// Link API
@ -155,8 +157,8 @@ namespace Kernel
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> listen_impl(int) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr&, int) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr&, int) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
@ -187,7 +189,7 @@ namespace Kernel
friend class Epoll;
friend class FileBackedRegion;
friend class OpenFileDescriptorSet;
friend class SharedFileData;
friend struct SharedFileData;
friend class TTY;
};

View File

@ -69,10 +69,6 @@ namespace Kernel
protected:
virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
// You may not write here and this is always non blocking
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); }
virtual BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); }
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
@ -114,27 +110,54 @@ namespace Kernel
class ProcSymlinkInode final : public TmpInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<ProcSymlinkInode>> create_new(BAN::ErrorOr<BAN::String> (*)(void*), void* data, TmpFileSystem&, mode_t, uid_t, gid_t);
~ProcSymlinkInode() = default;
static BAN::ErrorOr<BAN::RefPtr<ProcSymlinkInode>> create_new(BAN::ErrorOr<BAN::String> (*)(void*), void (*)(void*), void* data, TmpFileSystem&, mode_t, uid_t, gid_t);
~ProcSymlinkInode();
protected:
virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
// You may not write here and this is always non blocking
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); }
virtual BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); }
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override { return false; }
private:
ProcSymlinkInode(BAN::ErrorOr<BAN::String> (*callback)(void*), void* data, TmpFileSystem&, const TmpInodeInfo&);
ProcSymlinkInode(BAN::ErrorOr<BAN::String> (*callback)(void*), void (*destructor)(void*), void* data, TmpFileSystem&, const TmpInodeInfo&);
private:
BAN::ErrorOr<BAN::String> (*m_callback)(void*);
void (*m_destructor)(void*);
void* m_data;
};
class ProcFDDirectoryInode final : public TmpInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<ProcFDDirectoryInode>> create_new(Process&, TmpFileSystem&, mode_t);
~ProcFDDirectoryInode() = default;
virtual uid_t uid() const override { return m_process.credentials().ruid(); }
virtual gid_t gid() const override { return m_process.credentials().rgid(); }
protected:
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override;
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override { return BAN::Error::from_errno(EPERM); }
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override { return BAN::Error::from_errno(EPERM); }
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override { return BAN::Error::from_errno(EPERM); }
virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) override { return BAN::Error::from_errno(EPERM); }
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override { return BAN::Error::from_errno(EPERM); }
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override { return false; }
private:
ProcFDDirectoryInode(Process&, TmpFileSystem&, const TmpInodeInfo&);
private:
Process& m_process;
};
}

View File

@ -51,8 +51,6 @@ namespace Kernel
: m_info(info)
{}
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan buffer) override { return recvfrom_impl(buffer, nullptr, nullptr); }
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan buffer) override { return sendto_impl(buffer, nullptr, 0); }
BAN::ErrorOr<void> fsync_impl() final override { return {}; }
private:

View File

@ -157,6 +157,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override final;
virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) override final;
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
virtual bool can_read_impl() const override { return false; }
@ -168,6 +169,8 @@ namespace Kernel
template<TmpFuncs::for_each_valid_entry_callback F>
void for_each_valid_entry(F callback);
BAN::ErrorOr<void> unlink_inode(BAN::StringView, bool cleanup);
friend class TmpInode;
};

View File

@ -129,7 +129,8 @@ namespace Kernel
}
#if ARCH(i686)
void set_tls(uintptr_t addr);
void set_fsbase(uintptr_t addr);
void set_gsbase(uintptr_t addr);
#endif
private:
@ -153,8 +154,8 @@ namespace Kernel
BAN::Array<SegmentDescriptor, 7> m_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
static constexpr uint16_t m_tss_offset = 0x28;
#elif ARCH(i686)
BAN::Array<SegmentDescriptor, 8> m_gdt; // null, kernel code, kernel data, user code, user data, processor data, tls, tss
static constexpr uint16_t m_tss_offset = 0x38;
BAN::Array<SegmentDescriptor, 9> m_gdt; // null, kernel code, kernel data, user code, user data, processor data, fsbase, gsbase, tss
static constexpr uint16_t m_tss_offset = 0x40;
#endif
TaskStateSegment m_tss;
const GDTR m_gdtr {

View File

@ -33,6 +33,7 @@ namespace Kernel
BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override;
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> split(size_t offset) override;
protected:
BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;

View File

@ -15,6 +15,7 @@ namespace Kernel
~MemoryBackedRegion();
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> split(size_t offset) override;
BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }

View File

@ -33,6 +33,7 @@ namespace Kernel
bool contains(vaddr_t address) const;
bool contains_fully(vaddr_t address, size_t size) const;
bool overlaps(vaddr_t address, size_t size) const;
bool is_contained_by(vaddr_t address, size_t size) const;
bool writable() const { return m_flags & PageTable::Flags::ReadWrite; }
@ -59,6 +60,7 @@ namespace Kernel
BAN::ErrorOr<bool> allocate_page_containing(vaddr_t address, bool wants_write);
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) = 0;
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> split(size_t offset) = 0;
protected:
MemoryRegion(PageTable&, size_t size, Type type, PageTable::flags_t flags, int status_flags);
@ -68,7 +70,7 @@ namespace Kernel
protected:
PageTable& m_page_table;
const size_t m_size;
size_t m_size { 0 };
const Type m_type;
PageTable::flags_t m_flags;
const int m_status_flags;

View File

@ -58,6 +58,7 @@ namespace Kernel
static BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> create(BAN::RefPtr<SharedMemoryObjectManager::Object>, PageTable&, AddressRange);
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> split(size_t offset) override;
BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }

View File

@ -60,8 +60,8 @@ namespace Kernel
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<void> listen_impl(int) override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override;

View File

@ -33,9 +33,10 @@ namespace Kernel
protected:
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len) override;
virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); }
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override;
@ -63,6 +64,9 @@ namespace Kernel
SpinLock m_packet_lock;
ThreadBlocker m_packet_thread_blocker;
sockaddr_storage m_peer_address {};
socklen_t m_peer_address_len { 0 };
friend class BAN::RefPtr<UDPSocket>;
};

View File

@ -7,6 +7,7 @@
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/OpenFileDescriptorSet.h>
namespace Kernel
{
@ -16,6 +17,9 @@ namespace Kernel
BAN_NON_COPYABLE(UnixDomainSocket);
BAN_NON_MOVABLE(UnixDomainSocket);
public:
using FDWrapper = OpenFileDescriptorSet::FDWrapper;
public:
static BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> create(Socket::Type, const Socket::Info&);
BAN::ErrorOr<void> make_socket_pair(UnixDomainSocket&);
@ -25,8 +29,8 @@ namespace Kernel
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<void> listen_impl(int) override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
virtual bool can_read_impl() const override;
@ -38,8 +42,6 @@ namespace Kernel
UnixDomainSocket(Socket::Type, const Socket::Info&);
~UnixDomainSocket();
BAN::ErrorOr<void> add_packet(BAN::ConstByteSpan);
bool is_bound() const { return !m_bound_file.canonical_path.empty(); }
bool is_bound_to_unused() const { return !m_bound_file.inode; }
@ -54,7 +56,7 @@ namespace Kernel
BAN::WeakPtr<UnixDomainSocket> connection;
BAN::Queue<BAN::RefPtr<UnixDomainSocket>> pending_connections;
ThreadBlocker pending_thread_blocker;
SpinLock pending_lock;
Mutex pending_lock;
};
struct ConnectionlessInfo
@ -62,16 +64,25 @@ namespace Kernel
BAN::String peer_address;
};
struct PacketInfo
{
size_t size;
BAN::Vector<FDWrapper> fds;
BAN::Optional<struct ucred> ucred;
};
BAN::ErrorOr<void> add_packet(const msghdr&, PacketInfo&&);
private:
const Socket::Type m_socket_type;
VirtualFileSystem::File m_bound_file;
BAN::Variant<ConnectionInfo, ConnectionlessInfo> m_info;
BAN::CircularQueue<size_t, 128> m_packet_sizes;
BAN::CircularQueue<PacketInfo, 512> m_packet_infos;
size_t m_packet_size_total { 0 };
BAN::UniqPtr<VirtualRange> m_packet_buffer;
SpinLock m_packet_lock;
Mutex m_packet_lock;
ThreadBlocker m_packet_thread_blocker;
friend class BAN::RefPtr<UnixDomainSocket>;

View File

@ -33,7 +33,7 @@ namespace Kernel
BAN::ErrorOr<int> dup2(int, int);
BAN::ErrorOr<int> fcntl(int fd, int cmd, int extra);
BAN::ErrorOr<int> fcntl(int fd, int cmd, uintptr_t extra);
BAN::ErrorOr<off_t> seek(int fd, off_t offset, int whence);
BAN::ErrorOr<off_t> tell(int) const;
@ -51,8 +51,8 @@ namespace Kernel
BAN::ErrorOr<size_t> read_dir_entries(int fd, struct dirent* list, size_t list_len);
BAN::ErrorOr<size_t> recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<size_t> sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<size_t> recvmsg(int socket, msghdr& message, int flags);
BAN::ErrorOr<size_t> sendmsg(int socket, const msghdr& message, int flags);
BAN::ErrorOr<VirtualFileSystem::File> file_of(int) const;
BAN::ErrorOr<BAN::String> path_of(int) const;
@ -74,8 +74,8 @@ namespace Kernel
struct flock_t
{
bool locked;
bool shared;
bool locked { false };
bool shared { false };
ThreadBlocker thread_blocker;
BAN::HashSet<pid_t> lockers;
};
@ -109,6 +109,32 @@ namespace Kernel
BAN::ErrorOr<int> get_free_fd() const;
BAN::ErrorOr<void> get_free_fd_pair(int fds[2]) const;
public:
class FDWrapper
{
public:
FDWrapper(BAN::RefPtr<OpenFileDescription>);
FDWrapper(const FDWrapper& other) { *this = other; }
FDWrapper(FDWrapper&& other) { *this = BAN::move(other); }
~FDWrapper();
FDWrapper& operator=(const FDWrapper&);
FDWrapper& operator=(FDWrapper&&);
int fd() const { return m_fd; }
void clear();
private:
BAN::RefPtr<OpenFileDescription> m_description;
int m_fd { -1 };
friend class OpenFileDescriptorSet;
};
BAN::ErrorOr<FDWrapper> get_fd_wrapper(int fd);
size_t open_all_fd_wrappers(BAN::Span<FDWrapper> fd_wrappers);
private:
const Credentials& m_credentials;
mutable Mutex m_mutex;

View File

@ -19,15 +19,26 @@ namespace Kernel
asm volatile("cli");
const bool had_debug_lock = Debug::s_debug_lock.current_processor_has_lock();
bool first_panic = false;
{
SpinLockGuard _(Debug::s_debug_lock);
derrorln("Kernel panic at {}", location);
if (had_debug_lock)
derrorln(" while having debug lock...");
derrorln(message, BAN::forward<Args>(args)...);
if (!g_paniced)
{
g_paniced = true;
Debug::dump_stack_trace();
g_paniced = true;
first_panic = true;
}
}
if (first_panic)
Debug::dump_qr_code();
asm volatile("ud2");
__builtin_unreachable();
}

View File

@ -109,9 +109,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_access(const char* path, int amode);
BAN::ErrorOr<long> sys_create_dir(const char*, mode_t);
BAN::ErrorOr<long> sys_hardlinkat(int fd1, const char* path1, int fd2, const char* path2, int flag);
BAN::ErrorOr<long> sys_renameat(int oldfd, const char* old, int newfd, const char* _new);
BAN::ErrorOr<long> sys_unlinkat(int fd, const char* path, int flag);
BAN::ErrorOr<long> sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize);
BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2);
BAN::ErrorOr<long> sys_flock(int fd, int op);
@ -134,8 +134,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_bind(int socket, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<long> sys_connect(int socket, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<long> sys_listen(int socket, int backlog);
BAN::ErrorOr<long> sys_sendto(const sys_sendto_t*);
BAN::ErrorOr<long> sys_recvfrom(sys_recvfrom_t*);
BAN::ErrorOr<long> sys_recvmsg(int socket, msghdr* message, int flags);
BAN::ErrorOr<long> sys_sendmsg(int socket, const msghdr* message, int flags);
BAN::ErrorOr<long> sys_ioctl(int fildes, int request, void* arg);
@ -149,7 +149,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_pipe(int fildes[2]);
BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2);
BAN::ErrorOr<long> sys_fcntl(int fildes, int cmd, int extra);
BAN::ErrorOr<long> sys_fcntl(int fildes, int cmd, uintptr_t extra);
BAN::ErrorOr<long> sys_seek(int fd, off_t offset, int whence);
BAN::ErrorOr<long> sys_tell(int fd);
@ -172,6 +172,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_readdir(int fd, struct dirent* list, size_t list_len);
BAN::ErrorOr<BAN::Vector<BAN::UniqPtr<MemoryRegion>>> split_memory_region(BAN::UniqPtr<MemoryRegion>&& region, vaddr_t base, size_t length);
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*);
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
BAN::ErrorOr<long> sys_mprotect(void* addr, size_t len, int prot);
@ -191,7 +192,7 @@ namespace Kernel
void set_stopped(bool stopped, int signal);
void wait_while_stopped();
static BAN::ErrorOr<void> kill(pid_t pid, int signal);
static BAN::ErrorOr<void> kill(pid_t pid, int signal, const siginfo_t& = {});
BAN::ErrorOr<long> sys_kill(pid_t pid, int signal);
BAN::ErrorOr<long> sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact);
BAN::ErrorOr<long> sys_sigpending(sigset_t* set);
@ -202,8 +203,12 @@ namespace Kernel
BAN::ErrorOr<long> sys_futex(int op, const uint32_t* addr, uint32_t val, const timespec* abstime);
BAN::ErrorOr<long> sys_yield();
BAN::ErrorOr<long> sys_set_tls(void*);
BAN::ErrorOr<long> sys_get_tls();
BAN::ErrorOr<long> sys_set_fsbase(void*);
BAN::ErrorOr<long> sys_get_fsbase();
BAN::ErrorOr<long> sys_set_gsbase(void*);
BAN::ErrorOr<long> sys_get_gsbase();
BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg);
BAN::ErrorOr<long> sys_pthread_exit(void* value);
BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value);
@ -228,7 +233,8 @@ namespace Kernel
size_t proc_meminfo(off_t offset, BAN::ByteSpan) const;
size_t proc_cmdline(off_t offset, BAN::ByteSpan) const;
size_t proc_environ(off_t offset, BAN::ByteSpan) const;
BAN::ErrorOr<BAN::String> proc_executable() const;
BAN::ErrorOr<BAN::String> proc_cwd() const;
BAN::ErrorOr<BAN::String> proc_exe() const;
BAN::StringView executable() const { return m_executable; }
@ -240,6 +246,8 @@ namespace Kernel
// FIXME: remove this API
BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const;
OpenFileDescriptorSet& open_file_descriptor_set() { return m_open_file_descriptors; }
// ONLY CALLED BY TIMER INTERRUPT
static void update_alarm_queue();
@ -263,12 +271,17 @@ namespace Kernel
BAN::StringView file_name;
};
// Adds new region to the sorted array of mapped regions
BAN::ErrorOr<void> add_mapped_region(BAN::UniqPtr<MemoryRegion>&&);
// If address is contained by a region, returns the index of that.
// Otherwise returns the address of the first region after this address.
size_t find_mapped_region(vaddr_t) const;
BAN::ErrorOr<VirtualFileSystem::File> find_file(int fd, const char* path, int flags) const;
BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const;
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
BAN::ErrorOr<void> validate_string_access(const char*);
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write);
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write);
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
@ -278,7 +291,7 @@ namespace Kernel
return m_signal_pending_mask;
}
void add_pending_signal(uint8_t signal)
void add_pending_signal(uint8_t signal, const siginfo_t& info)
{
ASSERT(signal >= _SIGMIN);
ASSERT(signal <= _SIGMAX);
@ -290,6 +303,7 @@ namespace Kernel
if (handler == SIG_DFL && (signal == SIGCHLD || signal == SIGURG))
return;
m_signal_pending_mask |= 1ull << signal;
m_signal_infos[signal] = info;
}
void remove_pending_signal(uint8_t signal)
@ -342,6 +356,7 @@ namespace Kernel
uint64_t m_alarm_wake_time_ns { 0 };
mutable SpinLock m_signal_lock;
siginfo_t m_signal_infos[_SIGMAX + 1] { };
struct sigaction m_signal_handlers[_SIGMAX + 1] { };
uint64_t m_signal_pending_mask { 0 };

View File

@ -112,7 +112,9 @@ namespace Kernel
static void send_smp_message(ProcessorID, const SMPMessage&, bool send_ipi = true);
static void broadcast_smp_message(const SMPMessage&);
static void load_tls();
static void load_segments();
static void load_fsbase();
static void load_gsbase();
private:
Processor() = default;

View File

@ -59,8 +59,8 @@ namespace Kernel
bool can_add_signal_to_execute() const;
bool will_execute_signal() const;
// Returns true if handled signal had SA_RESTART
bool handle_signal(int signal = 0);
void add_signal(int signal);
bool handle_signal(int signal = 0, const siginfo_t& signal_info = {});
void add_signal(int signal, const siginfo_t& info);
void set_suspend_signal_mask(uint64_t sigmask);
static bool is_stopping_signal(int signal);
@ -122,8 +122,10 @@ namespace Kernel
void set_cpu_time_start();
void set_cpu_time_stop();
void set_tls(vaddr_t tls) { m_tls = tls; }
vaddr_t get_tls() const { return m_tls; }
void set_fsbase(vaddr_t base) { m_fsbase = base; }
vaddr_t get_fsbase() const { return m_fsbase; }
void set_gsbase(vaddr_t base) { m_gsbase = base; }
vaddr_t get_gsbase() const { return m_gsbase; }
size_t virtual_page_count() const { return (m_kernel_stack ? (m_kernel_stack->size() / PAGE_SIZE) : 0) + (m_userspace_stack ? (m_userspace_stack->size() / PAGE_SIZE) : 0); }
size_t physical_page_count() const { return virtual_page_count(); }
@ -164,13 +166,15 @@ namespace Kernel
bool m_is_userspace { false };
bool m_delete_process { false };
vaddr_t m_tls { 0 };
vaddr_t m_fsbase { 0 };
vaddr_t m_gsbase { 0 };
SchedulerQueue::Node* m_scheduler_node { nullptr };
InterruptStack m_interrupt_stack { };
InterruptRegisters m_interrupt_registers { };
siginfo_t m_signal_infos[_SIGMAX + 1] { };
uint64_t m_signal_pending_mask { 0 };
uint64_t m_signal_block_mask { 0 };
BAN::Optional<uint64_t> m_signal_suspend_mask;

View File

@ -1,7 +0,0 @@
#pragma once
#include <BAN/Formatter.h>
#include <kernel/Terminal/TTY.h>
#define kprint(...) BAN::Formatter::print(Kernel::TTY::putchar_current, __VA_ARGS__)
#define kprintln(...) BAN::Formatter::println(Kernel::TTY::putchar_current, __VA_ARGS__)

View File

@ -856,7 +856,7 @@ acpi_release_global_lock:
};
// TODO: EC can also reside in memory space
auto crs_buffer = BAN::ConstByteSpan { crs.as.str_buf->bytes, crs.as.str_buf->size };
auto crs_buffer = BAN::ConstByteSpan { crs.as.str_buf->bytes, static_cast<size_t>(crs.as.str_buf->size) };
const auto data_port = TRY(extract_io_port(crs_buffer));
const auto command_port = TRY(extract_io_port(crs_buffer));

View File

@ -56,7 +56,7 @@ namespace Kernel::ACPI
EmbeddedController::~EmbeddedController()
{
if (m_thread)
m_thread->add_signal(SIGKILL);
m_thread->add_signal(SIGKILL, {});
m_thread = nullptr;
}

View File

@ -1,4 +1,5 @@
#include <kernel/Debug.h>
#include <kernel/Device/FramebufferDevice.h>
#include <kernel/InterruptController.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Memory/PageTable.h>
@ -6,6 +7,9 @@
#include <kernel/Terminal/TTY.h>
#include <kernel/Timer/Timer.h>
#include <LibDEFLATE/Compressor.h>
#include <LibQR/QRCode.h>
#include <ctype.h>
bool g_disable_debug = false;
@ -15,6 +19,15 @@ namespace Debug
Kernel::RecursiveSpinLock s_debug_lock;
static constexpr char s_panic_url_prefix[] = "https://bananymous.com/panic#";
static constexpr size_t s_qr_code_max_capacity { 2953 };
static bool s_qr_code_shown { false };
static char s_debug_buffer[16 * 1024] {};
static size_t s_debug_buffer_tail { 0 };
static size_t s_debug_buffer_size { 0 };
static uint8_t s_debug_ansi_state { 0 };
void dump_stack_trace()
{
using namespace Kernel;
@ -72,17 +85,203 @@ namespace Debug
BAN::Formatter::print(Debug::putchar, "\e[m");
}
static void queue_debug_buffer(char ch)
{
switch (s_debug_ansi_state)
{
case 1:
if (ch == '[')
{
s_debug_ansi_state = 2;
break;
}
s_debug_ansi_state = 0;
[[fallthrough]];
case 0:
if (ch == '\e')
{
s_debug_ansi_state = 1;
break;
}
if (!isprint(ch) && ch != '\n')
break;
s_debug_buffer[(s_debug_buffer_tail + s_debug_buffer_size) % sizeof(s_debug_buffer)] = ch;
if (s_debug_buffer_size < sizeof(s_debug_buffer))
s_debug_buffer_size++;
else
s_debug_buffer_tail = (s_debug_buffer_tail + 1) % sizeof(s_debug_buffer);
break;
case 2:
if (isalpha(ch))
s_debug_ansi_state = 0;
break;
}
}
static void reverse(char* first, char* last)
{
const size_t len = last - first;
for (size_t i = 0; i < len / 2; i++)
BAN::swap(first[i], first[len - i - 1]);
}
static void rotate(char* first, char* middle, char* last)
{
reverse(first, middle);
reverse(middle, last);
reverse(first, last);
}
static BAN::ErrorOr<BAN::Vector<uint8_t>> compress_kernel_logs()
{
constexpr size_t max_size = ((s_qr_code_max_capacity + 3) / 4 * 3) - sizeof(s_panic_url_prefix);
BAN::Vector<uint8_t> result;
size_t l = 0, r = s_debug_buffer_size;
while (l + 50 < r)
{
const size_t middle = (l + r) / 2;
const uint8_t* base = reinterpret_cast<const uint8_t*>(s_debug_buffer) + s_debug_buffer_size - middle;
auto compressed = TRY(LibDEFLATE::Compressor({ base, middle }, LibDEFLATE::StreamType::Zlib).compress());
if (compressed.size() > max_size)
r = middle;
else
{
l = middle;
result = BAN::move(compressed);
}
}
return result;
}
void dump_qr_code()
{
ASSERT(Kernel::g_paniced);
auto boot_framebuffer = Kernel::FramebufferDevice::boot_framebuffer();
if (!boot_framebuffer)
{
derrorln("No boot framebuffer, not generating QR code");
return;
}
if (boot_framebuffer->width() < 177 + 8 || boot_framebuffer->height() < 177 + 8)
{
derrorln("Boot framebuffer is too small for a qr code");
return;
}
// rotate logs to start from index 0 and be contiguous
rotate(s_debug_buffer, s_debug_buffer + s_debug_buffer_tail, s_debug_buffer + sizeof(s_debug_buffer));
auto compressed_or_error = compress_kernel_logs();
if (compressed_or_error.is_error())
{
// TODO: send uncompressed logs?
derrorln("Failed to compress kernel logs: {}", compressed_or_error.error());
return;
}
auto compressed = compressed_or_error.release_value();
static uint8_t qr_code_data[s_qr_code_max_capacity];
size_t qr_code_data_len = 0;
for (size_t i = 0; s_panic_url_prefix[i]; i++)
qr_code_data[qr_code_data_len++] = s_panic_url_prefix[i];
constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
for (size_t i = 0; i < compressed.size() / 3; i++)
{
const uint32_t bits =
((compressed[3 * i + 0]) << 16) |
((compressed[3 * i + 1]) << 8) |
((compressed[3 * i + 2]) << 0);
qr_code_data[qr_code_data_len++] = alphabet[(bits >> 18) & 0x3F];
qr_code_data[qr_code_data_len++] = alphabet[(bits >> 12) & 0x3F];
qr_code_data[qr_code_data_len++] = alphabet[(bits >> 6) & 0x3F];
qr_code_data[qr_code_data_len++] = alphabet[(bits >> 0) & 0x3F];
}
switch (compressed.size() % 3)
{
case 0:
break;
case 1:
{
const uint16_t bits =
(compressed[compressed.size() - 1] << 4);
qr_code_data[qr_code_data_len++] = alphabet[(bits >> 6) & 0x3F];
qr_code_data[qr_code_data_len++] = alphabet[(bits >> 0) & 0x3F];
break;
}
case 2:
{
const uint32_t bits =
(compressed[compressed.size() - 2] << 10) |
(compressed[compressed.size() - 1] << 2);
qr_code_data[qr_code_data_len++] = alphabet[(bits >> 12) & 0x3F];
qr_code_data[qr_code_data_len++] = alphabet[(bits >> 6) & 0x3F];
qr_code_data[qr_code_data_len++] = alphabet[(bits >> 0) & 0x3F];
break;
}
}
auto qr_or_error = LibQR::QRCode::generate({ qr_code_data, qr_code_data_len });
if (qr_or_error.is_error())
{
derrorln("Failed to generate QR code");
return;
}
auto qr_code = qr_or_error.release_value();
// after this point no more logs are printed to framebuffer
s_qr_code_shown = true;
const size_t min_framebuffer_dimension = BAN::Math::min(boot_framebuffer->width(), boot_framebuffer->height());
const size_t module_size = min_framebuffer_dimension / (qr_code.size() + 8);
for (size_t y = 0; y < (qr_code.size() + 8) * module_size; y++)
for (size_t x = 0; x < (qr_code.size() + 8) * module_size; x++)
boot_framebuffer->set_pixel(x, y, 0xFFFFFF);
for (size_t y = 0; y < qr_code.size(); y++)
{
for (size_t x = 0; x < qr_code.size(); x++)
{
if (!qr_code.get(x, y))
continue;
for (size_t i = 0; i < module_size; i++)
for (size_t j = 0; j < module_size; j++)
boot_framebuffer->set_pixel((x + 4) * module_size + j, (y + 4) * module_size + i, 0x000000);
}
}
boot_framebuffer->sync_pixels_rectangle(0, 0, (qr_code.size() + 8) * module_size, (qr_code.size() + 8) * module_size);
}
void putchar(char ch)
{
using namespace Kernel;
if (!g_paniced)
queue_debug_buffer(ch);
if (g_disable_debug)
return;
if (Kernel::Serial::has_devices())
return Kernel::Serial::putchar_any(ch);
if (Kernel::TTY::is_initialized())
{
if (s_qr_code_shown)
return;
return Kernel::TTY::putchar_current(ch);
}
if (g_terminal_driver)
{

View File

@ -12,12 +12,19 @@
namespace Kernel
{
static BAN::RefPtr<FramebufferDevice> s_boot_framebuffer;
static uint32_t get_framebuffer_device_index()
{
static uint32_t index = 0;
return index++;
}
BAN::RefPtr<FramebufferDevice> FramebufferDevice::boot_framebuffer()
{
return s_boot_framebuffer;
}
BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> FramebufferDevice::create_from_boot_framebuffer()
{
ASSERT(g_boot_info.framebuffer.type == FramebufferInfo::Type::RGB);
@ -37,6 +44,7 @@ namespace Kernel
auto device = BAN::RefPtr<FramebufferDevice>::adopt(device_ptr);
TRY(device->initialize());
DevFileSystem::get().add_device(device);
s_boot_framebuffer = device;
return device;
}
@ -293,6 +301,13 @@ namespace Kernel
return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
}
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> split(size_t offset) override
{
(void)offset;
dwarnln("TODO: FramebufferMemoryRegion::split");
return BAN::Error::from_errno(ENOTSUP);
}
protected:
// Returns error if no memory was available
// Returns true if page was succesfully allocated

View File

@ -2,6 +2,7 @@
#include <BAN/ScopeGuard.h>
#include <kernel/FS/Ext2/FileSystem.h>
#include <kernel/FS/Ext2/Inode.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Timer/Timer.h>
#include <sys/stat.h>
@ -114,8 +115,11 @@ namespace Kernel
TRY(result.append(BAN::StringView(reinterpret_cast<const char*>(m_inode.block), m_inode.size)));
return result;
}
dwarnln("TODO: ext2 get symlink target from {} byte inode", m_inode.size);
return BAN::Error::from_errno(ENOTSUP);
BAN::String result;
TRY(result.resize(m_inode.size));
TRY(read_impl(0, { reinterpret_cast<uint8_t*>(result.data()), result.size() }));
return BAN::move(result);
}
BAN::ErrorOr<void> Ext2Inode::set_link_target_impl(BAN::StringView target)
@ -129,8 +133,10 @@ namespace Kernel
TRY(sync());
return {};
}
dwarnln("TODO: ext2 set symlink target to {} bytes from {} byte inode", target.size(), m_inode.size);
return BAN::Error::from_errno(ENOTSUP);
TRY(truncate_impl(target.size()));
TRY(write_impl(0, { reinterpret_cast<const uint8_t*>(target.data()), target.size() }));
return {};
}
BAN::ErrorOr<size_t> Ext2Inode::read_impl(off_t offset, BAN::ByteSpan buffer)
@ -580,6 +586,37 @@ done:
return {};
}
BAN::ErrorOr<void> Ext2Inode::rename_inode_impl(BAN::RefPtr<Inode> old_parent, BAN::StringView old_name, BAN::StringView new_name)
{
ASSERT(this->mode().ifdir());
ASSERT(old_parent->mode().ifdir());
ASSERT(&m_fs == old_parent->filesystem());
auto* ext2_parent = static_cast<Ext2Inode*>(old_parent.ptr());
// FIXME: possible deadlock :)
LockGuard _(ext2_parent->m_mutex);
auto old_inode = TRY(ext2_parent->find_inode_impl(old_name));
auto* ext2_inode = static_cast<Ext2Inode*>(old_inode.ptr());
if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error())
{
if (replace_or_error.error().get_error_code() != ENOENT)
return replace_or_error.release_error();
}
else
{
TRY(unlink_impl(new_name));
}
TRY(link_inode_to_directory(*ext2_inode, new_name));
TRY(ext2_parent->remove_inode_from_directory(old_name, false));
return {};
}
BAN::ErrorOr<void> Ext2Inode::link_inode_to_directory(Ext2Inode& inode, BAN::StringView name)
{
if (!this->mode().ifdir())
@ -773,7 +810,7 @@ needs_new_block:
return {};
}
BAN::ErrorOr<void> Ext2Inode::unlink_impl(BAN::StringView name)
BAN::ErrorOr<void> Ext2Inode::remove_inode_from_directory(BAN::StringView name, bool cleanup_directory)
{
ASSERT(mode().ifdir());
if (m_inode.flags & Ext2::Enum::INDEX_FL)
@ -797,7 +834,7 @@ needs_new_block:
if (entry.inode && name == BAN::StringView(entry.name, entry.name_len))
{
auto inode = TRY(Ext2Inode::create(m_fs, entry.inode));
if (inode->mode().ifdir())
if (cleanup_directory && inode->mode().ifdir())
{
if (!TRY(inode->is_directory_empty()))
return BAN::Error::from_errno(ENOTEMPTY);
@ -831,6 +868,12 @@ needs_new_block:
return {};
}
BAN::ErrorOr<void> Ext2Inode::unlink_impl(BAN::StringView name)
{
TRY(remove_inode_from_directory(name, true));
return {};
}
BAN::ErrorOr<uint32_t> Ext2Inode::allocate_new_block_to_indirect_block(uint32_t& block, uint32_t index, uint32_t depth)
{
const uint32_t inode_blocks_per_fs_block = blksize() / 512;

View File

@ -114,6 +114,20 @@ namespace Kernel
return link_inode_impl(name, inode);
}
BAN::ErrorOr<void> Inode::rename_inode(BAN::RefPtr<Inode> old_parent, BAN::StringView old_name, BAN::StringView new_name)
{
LockGuard _(m_mutex);
if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (!old_parent->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (this->filesystem() != old_parent->filesystem())
return BAN::Error::from_errno(EXDEV);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS);
return rename_inode_impl(old_parent, old_name, new_name);
}
BAN::ErrorOr<void> Inode::unlink(BAN::StringView name)
{
LockGuard _(m_mutex);
@ -176,21 +190,21 @@ namespace Kernel
return listen_impl(backlog);
}
BAN::ErrorOr<size_t> Inode::sendto(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len)
BAN::ErrorOr<size_t> Inode::recvmsg(msghdr& message, int flags)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return sendto_impl(message, address, address_len);
};
return recvmsg_impl(message, flags);
}
BAN::ErrorOr<size_t> Inode::recvfrom(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len)
BAN::ErrorOr<size_t> Inode::sendmsg(const msghdr& message, int flags)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return recvfrom_impl(buffer, address, address_len);
};
return sendmsg_impl(message, flags);
}
BAN::ErrorOr<void> Inode::getsockname(sockaddr* address, socklen_t* address_len)
{

View File

@ -106,7 +106,7 @@ namespace Kernel
{
if (m_reading_count == 0)
{
Thread::current().add_signal(SIGPIPE);
Thread::current().add_signal(SIGPIPE, {});
return BAN::Error::from_errno(EPIPE);
}
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));

View File

@ -43,7 +43,7 @@ namespace Kernel
[](void*) -> BAN::ErrorOr<BAN::String> {
return BAN::String::formatted("{}", Process::current().pid());
},
nullptr, *s_instance, 0444, 0, 0)
nullptr, nullptr, *s_instance, 0444, 0, 0)
);
MUST(static_cast<TmpDirectoryInode*>(s_instance->root_inode().ptr())->link_inode(*self_inode, "self"_sv));
}

View File

@ -1,5 +1,7 @@
#include <kernel/FS/ProcFS/Inode.h>
#include <ctype.h>
namespace Kernel
{
@ -15,9 +17,11 @@ namespace Kernel
TRY(inode->link_inode(*inode, "."_sv));
TRY(inode->link_inode(static_cast<TmpInode&>(*fs.root_inode()), ".."_sv));
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_meminfo, fs, 0400)), "meminfo"_sv));
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_cmdline, fs, 0400)), "cmdline"_sv));
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_cmdline, fs, 0444)), "cmdline"_sv));
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_environ, fs, 0400)), "environ"_sv));
TRY(inode->link_inode(*MUST(ProcSymlinkProcessInode::create_new(process, &Process::proc_executable, fs, 0400)), "exe"_sv));
TRY(inode->link_inode(*MUST(ProcSymlinkProcessInode::create_new(process, &Process::proc_cwd, fs, 0777)), "cwd"_sv));
TRY(inode->link_inode(*MUST(ProcSymlinkProcessInode::create_new(process, &Process::proc_exe, fs, 0777)), "exe"_sv));
TRY(inode->link_inode(*MUST(ProcFDDirectoryInode::create_new(process, fs, 0777)), "fd"_sv));
return inode;
}
@ -33,7 +37,9 @@ namespace Kernel
(void)TmpDirectoryInode::unlink_impl("meminfo"_sv);
(void)TmpDirectoryInode::unlink_impl("cmdline"_sv);
(void)TmpDirectoryInode::unlink_impl("environ"_sv);
(void)TmpDirectoryInode::unlink_impl("cwd"_sv);
(void)TmpDirectoryInode::unlink_impl("exe"_sv);
(void)TmpDirectoryInode::unlink_impl("fd"_sv);
}
BAN::ErrorOr<BAN::RefPtr<ProcROProcessInode>> ProcROProcessInode::create_new(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem& fs, mode_t mode)
@ -108,27 +114,123 @@ namespace Kernel
return m_callback(offset, buffer);
}
BAN::ErrorOr<BAN::RefPtr<ProcSymlinkInode>> ProcSymlinkInode::create_new(BAN::ErrorOr<BAN::String> (*callback)(void*), void* data, TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
BAN::ErrorOr<BAN::RefPtr<ProcSymlinkInode>> ProcSymlinkInode::create_new(BAN::ErrorOr<BAN::String> (*callback)(void*), void (*destructor)(void*), void* data, TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
{
auto inode_info = create_inode_info(Mode::IFLNK | mode, uid, gid);
auto* inode_ptr = new ProcSymlinkInode(callback, data, fs, inode_info);
auto* inode_ptr = new ProcSymlinkInode(callback, destructor, data, fs, inode_info);
if (inode_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<ProcSymlinkInode>::adopt(inode_ptr);
}
ProcSymlinkInode::ProcSymlinkInode(BAN::ErrorOr<BAN::String> (*callback)(void*), void* data, TmpFileSystem& fs, const TmpInodeInfo& inode_info)
ProcSymlinkInode::ProcSymlinkInode(BAN::ErrorOr<BAN::String> (*callback)(void*), void (*destructor)(void*), void* data, TmpFileSystem& fs, const TmpInodeInfo& inode_info)
: TmpInode(fs, MUST(fs.allocate_inode(inode_info)), inode_info)
, m_callback(callback)
, m_destructor(destructor)
, m_data(data)
{
m_inode_info.mode |= Inode::Mode::IFLNK;
}
ProcSymlinkInode::~ProcSymlinkInode()
{
if (m_destructor)
m_destructor(m_data);
}
BAN::ErrorOr<BAN::String> ProcSymlinkInode::link_target_impl()
{
return m_callback(m_data);
}
BAN::ErrorOr<BAN::RefPtr<ProcFDDirectoryInode>> ProcFDDirectoryInode::create_new(Process& process, TmpFileSystem& fs, mode_t mode)
{
auto inode_info = create_inode_info(Mode::IFDIR | mode, 0, 0);
auto* inode_ptr = new ProcFDDirectoryInode(process, fs, inode_info);
if (inode_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<ProcFDDirectoryInode>::adopt(inode_ptr);
}
ProcFDDirectoryInode::ProcFDDirectoryInode(Process& process, TmpFileSystem& fs, const TmpInodeInfo& inode_info)
: TmpInode(fs, MUST(fs.allocate_inode(inode_info)), inode_info)
, m_process(process)
{
ASSERT(mode().ifdir());
}
BAN::ErrorOr<BAN::RefPtr<Inode>> ProcFDDirectoryInode::find_inode_impl(BAN::StringView name)
{
int fd = 0;
for (char ch : name)
{
if (!isdigit(ch))
return BAN::Error::from_errno(ENOENT);
fd = (fd * 10) + (ch - '0');
if (fd > OPEN_MAX)
return BAN::Error::from_errno(ENOENT);
}
auto path_or_error = m_process.open_file_descriptor_set().path_of(fd);
if (path_or_error.is_error())
return BAN::Error::from_errno(ENOENT);
auto* data = new BAN::String();
if (data == nullptr)
return BAN::Error::from_errno(ENOMEM);
*data = BAN::move(path_or_error.release_value());
auto inode = TRY(ProcSymlinkInode::create_new(
[](void* data) -> BAN::ErrorOr<BAN::String>
{
BAN::String result;
TRY(result.append(*static_cast<BAN::String*>(data)));
return result;
},
[](void* data) -> void
{
delete static_cast<BAN::String*>(data);
},
data, m_fs, 0777, uid(), gid()
));
return BAN::RefPtr<Inode>(BAN::move(inode));
}
BAN::ErrorOr<size_t> ProcFDDirectoryInode::list_next_inodes_impl(off_t offset, struct dirent* list, size_t list_len)
{
if (list_len == 0)
return BAN::Error::from_errno(ENOBUFS);
auto& ofds = m_process.open_file_descriptor_set();
for (size_t fd = 0; fd < OPEN_MAX; fd++)
{
if (ofds.inode_of(fd).is_error())
continue;
if (offset-- > 0)
continue;
list[0] = {
.d_ino = 0,
.d_type = DT_LNK,
.d_name = {},
};
size_t index = 0;
BAN::Formatter::print(
[&](char ch) {
list[0].d_name[index++] = ch;
list[0].d_name[index] = '\0';
}, "{}", fd
);
return 1;
}
return 0;
}
}

View File

@ -669,7 +669,44 @@ namespace Kernel
return {};
}
BAN::ErrorOr<void> TmpDirectoryInode::rename_inode_impl(BAN::RefPtr<Inode> old_parent, BAN::StringView old_name, BAN::StringView new_name)
{
ASSERT(this->mode().ifdir());
ASSERT(old_parent->mode().ifdir());
ASSERT(&m_fs == old_parent->filesystem());
auto* tmp_parent = static_cast<TmpDirectoryInode*>(old_parent.ptr());
// FIXME: possible deadlock :)
LockGuard _(tmp_parent->m_mutex);
auto old_inode = TRY(tmp_parent->find_inode_impl(old_name));
auto* tmp_inode = static_cast<TmpInode*>(old_inode.ptr());
if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error())
{
if (replace_or_error.error().get_error_code() != ENOENT)
return replace_or_error.release_error();
}
else
{
TRY(unlink_impl(new_name));
}
TRY(link_inode(*tmp_inode, new_name));
TRY(tmp_parent->unlink_inode(old_name, false));
return {};
}
BAN::ErrorOr<void> TmpDirectoryInode::unlink_impl(BAN::StringView name)
{
TRY(unlink_inode(name, true));
return {};
}
BAN::ErrorOr<void> TmpDirectoryInode::unlink_inode(BAN::StringView name, bool cleanup)
{
ino_t entry_ino = 0;
@ -687,6 +724,7 @@ namespace Kernel
ASSERT(inode->nlink() > 0);
if (cleanup)
TRY(inode->prepare_unlink());
inode->m_inode_info.nlink--;

View File

@ -29,7 +29,8 @@ namespace Kernel
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, data_flags); // user data
#if ARCH(i686)
gdt->write_entry(0x28, reinterpret_cast<uint32_t>(processor), sizeof(Processor), 0x92, 0x4); // processor data
gdt->write_entry(0x30, 0x00000000, 0x00000, 0x00, 0x0); // tls
gdt->write_entry(0x30, 0x00000000, 0x00000, 0xF2, data_flags); // fsbase
gdt->write_entry(0x38, 0x00000000, 0x00000, 0xF2, data_flags); // gsbase
#endif
gdt->write_tss();
@ -37,10 +38,14 @@ namespace Kernel
}
#if ARCH(i686)
void GDT::set_tls(uintptr_t addr)
void GDT::set_fsbase(uintptr_t addr)
{
write_entry(0x30, addr, 0xFFFF, 0xF2, 0xC);
}
void GDT::set_gsbase(uintptr_t addr)
{
write_entry(0x38, addr, 0xFFFF, 0xF2, 0xC);
}
#endif
void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)

View File

@ -203,7 +203,7 @@ namespace Kernel
if (result.is_error())
{
dwarnln("Demand paging: {}", result.error());
Thread::current().handle_signal(SIGKILL);
Thread::current().handle_signal(SIGKILL, {});
goto done;
}
}
@ -236,11 +236,15 @@ namespace Kernel
"Register dump\r\n"
"rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n"
"rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n"
" r8=0x{16H}, r9=0x{16H}, r10=0x{16H}, r11=0x{16H}\r\n"
"r12=0x{16H}, r13=0x{16H}, r14=0x{16H}, r15=0x{16H}\r\n"
"rip=0x{16H}, rflags=0x{16H}\r\n"
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}",
Processor::current_id(), isr_exceptions[isr], error, pid, tid, process_name,
regs->rax, regs->rbx, regs->rcx, regs->rdx,
interrupt_stack->sp, regs->rbp, regs->rdi, regs->rsi,
regs->r8, regs->r9, regs->r10, regs->r11,
regs->r12, regs->r13, regs->r14, regs->r15,
interrupt_stack->ip, interrupt_stack->flags,
regs->cr0, regs->cr2, regs->cr3, regs->cr4
);
@ -269,30 +273,48 @@ namespace Kernel
{
// TODO: Confirm and fix the exception to signal mappings
int signal = 0;
siginfo_t signal_info {};
switch (isr)
{
case ISR::DivisionError:
signal_info.si_signo = SIGFPE;
signal_info.si_code = FPE_INTDIV;
break;
case ISR::SIMDFloatingPointException:
case ISR::x87FloatingPointException:
signal = SIGFPE;
// FIXME: this is probably not correct?
signal_info.si_signo = SIGFPE;
signal_info.si_code = FPE_FLTDIV;
break;
case ISR::AlignmentCheck:
signal = SIGBUS;
signal_info.si_signo = SIGBUS;
signal_info.si_code = BUS_ADRALN;
break;
case ISR::GeneralProtectionFault:
// TODO: this assumes unaligned operand but GP can be also caused by
// a privileged instruction or uncanonical address in which case
// the generated signal should be different
signal_info.si_signo = SIGBUS;
signal_info.si_code = BUS_ADRALN;
break;
case ISR::InvalidOpcode:
signal = SIGILL;
signal_info.si_signo = SIGILL;
signal_info.si_code = ILL_ILLOPC;
break;
case ISR::PageFault:
signal = SIGSEGV;
signal_info.si_signo = SIGSEGV;
if (PageTable::current().get_page_flags(regs->cr2 & PAGE_ADDR_MASK) & PageTable::Flags::Present)
signal_info.si_code = SEGV_ACCERR;
else
signal_info.si_code = SEGV_MAPERR;
break;
default:
dwarnln("Unhandled exception");
signal = SIGABRT;
signal_info.si_signo = SIGABRT;
break;
}
Thread::current().handle_signal(signal);
Thread::current().handle_signal(signal_info.si_signo, signal_info);
}
else
{

View File

@ -321,7 +321,7 @@ namespace Kernel::Input
result.type = type;
BAN::Optional<ACPI::ResourceData> data;
ACPI::ResourceParser parser({ crs_obj->node.as.str_buf->bytes, crs_obj->node.as.str_buf->size });
ACPI::ResourceParser parser({ crs_obj->node.as.str_buf->bytes, static_cast<size_t>(crs_obj->node.as.str_buf->size) });
while ((data = parser.get_next()).has_value())
{
switch (data->type)

View File

@ -232,4 +232,33 @@ namespace Kernel
return BAN::UniqPtr<MemoryRegion>(BAN::move(result));
}
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FileBackedRegion::split(size_t offset)
{
ASSERT(offset && offset < m_size);
ASSERT(offset % PAGE_SIZE == 0);
const bool has_dirty_pages = (m_type == Type::PRIVATE);
BAN::Vector<paddr_t> dirty_pages;
if (has_dirty_pages)
{
TRY(dirty_pages.resize(BAN::Math::div_round_up<size_t>(m_size - offset, PAGE_SIZE)));
for (size_t i = 0; i < dirty_pages.size(); i++)
dirty_pages[i] = m_dirty_pages[i + offset / PAGE_SIZE];
}
auto* new_region = new FileBackedRegion(m_inode, m_page_table, m_offset + offset, m_size - offset, m_type, m_flags, m_status_flags);
if (new_region == nullptr)
return BAN::Error::from_errno(ENOTSUP);
new_region->m_vaddr = m_vaddr + offset;
new_region->m_shared_data = m_shared_data;
new_region->m_dirty_pages = BAN::move(dirty_pages);
m_size = offset;
if (has_dirty_pages)
MUST(m_dirty_pages.resize(offset / PAGE_SIZE));
return BAN::UniqPtr<MemoryRegion>::adopt(new_region);
}
}

View File

@ -82,6 +82,21 @@ namespace Kernel
return BAN::UniqPtr<MemoryRegion>(BAN::move(result));
}
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> MemoryBackedRegion::split(size_t offset)
{
ASSERT(offset && offset < m_size);
ASSERT(offset % PAGE_SIZE == 0);
auto* new_region = new MemoryBackedRegion(m_page_table, m_size - offset, m_type, m_flags, m_status_flags);
if (new_region == nullptr)
return BAN::Error::from_errno(ENOMEM);
new_region->m_vaddr = m_vaddr + offset;
m_size = offset;
return BAN::UniqPtr<MemoryRegion>::adopt(new_region);
}
BAN::ErrorOr<void> MemoryBackedRegion::copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size)
{
ASSERT(offset_into_region + buffer_size <= m_size);

View File

@ -50,6 +50,11 @@ namespace Kernel
return true;
}
bool MemoryRegion::is_contained_by(vaddr_t address, size_t size) const
{
return address <= m_vaddr && m_vaddr + m_size <= address + size;
}
BAN::ErrorOr<void> MemoryRegion::mprotect(PageTable::flags_t new_page_flags)
{
if (m_flags == new_page_flags)

View File

@ -87,6 +87,13 @@ namespace Kernel
return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
}
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> SharedMemoryObject::split(size_t offset)
{
(void)offset;
dwarnln("TODO: SharedMemoryObject::split");
return BAN::Error::from_errno(ENOTSUP);
}
BAN::ErrorOr<bool> SharedMemoryObject::allocate_page_containing_impl(vaddr_t address, bool wants_write)
{
ASSERT(contains(address));

View File

@ -1,5 +1,4 @@
#include <BAN/Errors.h>
#include <kernel/kprint.h>
#include <kernel/BootInfo.h>
#include <kernel/Memory/kmalloc.h>
@ -153,13 +152,13 @@ void kmalloc_dump_info()
{
Kernel::SpinLockGuard _(s_kmalloc_lock);
kprintln("kmalloc: 0x{8H}->0x{8H}", s_kmalloc_info.base, s_kmalloc_info.end);
kprintln(" used: 0x{8H}", s_kmalloc_info.used);
kprintln(" free: 0x{8H}", s_kmalloc_info.free);
dprintln("kmalloc: 0x{8H}->0x{8H}", s_kmalloc_info.base, s_kmalloc_info.end);
dprintln(" used: 0x{8H}", s_kmalloc_info.used);
dprintln(" free: 0x{8H}", s_kmalloc_info.free);
kprintln("kmalloc fixed {} byte: 0x{8H}->0x{8H}", sizeof(kmalloc_fixed_info::node), s_kmalloc_fixed_info.base, s_kmalloc_fixed_info.end);
kprintln(" used: 0x{8H}", s_kmalloc_fixed_info.used);
kprintln(" free: 0x{8H}", s_kmalloc_fixed_info.free);
dprintln("kmalloc fixed {} byte: 0x{8H}->0x{8H}", sizeof(kmalloc_fixed_info::node), s_kmalloc_fixed_info.base, s_kmalloc_fixed_info.end);
dprintln(" used: 0x{8H}", s_kmalloc_fixed_info.used);
dprintln(" free: 0x{8H}", s_kmalloc_fixed_info.free);
}
static bool is_corrupted()

View File

@ -36,7 +36,7 @@ namespace Kernel
ARPTable::~ARPTable()
{
if (m_thread)
m_thread->add_signal(SIGKILL);
m_thread->add_signal(SIGKILL, {});
m_thread = nullptr;
}

View File

@ -47,7 +47,7 @@ namespace Kernel
IPv4Layer::~IPv4Layer()
{
if (m_thread)
m_thread->add_signal(SIGKILL);
m_thread->add_signal(SIGKILL, {});
m_thread = nullptr;
}

View File

@ -190,8 +190,21 @@ namespace Kernel
return m_network_layer.bind_socket_to_address(this, address, address_len);
}
BAN::ErrorOr<size_t> TCPSocket::recvfrom_impl(BAN::ByteSpan buffer, sockaddr*, socklen_t*)
BAN::ErrorOr<size_t> TCPSocket::recvmsg_impl(msghdr& message, int flags)
{
flags &= (MSG_OOB | MSG_PEEK | MSG_WAITALL);
if (flags != 0)
{
dwarnln("TODO: recvmsg with flags 0x{H}", flags);
return BAN::Error::from_errno(ENOTSUP);
}
if (CMSG_FIRSTHDR(&message))
{
dwarnln("ignoring recvmsg control message");
message.msg_controllen = 0;
}
if (!m_has_connected)
return BAN::Error::from_errno(ENOTCONN);
@ -202,26 +215,43 @@ namespace Kernel
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
}
const uint32_t to_recv = BAN::Math::min<uint32_t>(buffer.size(), m_recv_window.data_size);
message.msg_flags = 0;
size_t total_recv = 0;
for (int i = 0; i < message.msg_iovlen; i++)
{
auto* recv_buffer = reinterpret_cast<uint8_t*>(m_recv_window.buffer->vaddr());
memcpy(buffer.data(), recv_buffer, to_recv);
m_recv_window.data_size -= to_recv;
m_recv_window.start_seq += to_recv;
if (m_recv_window.data_size > 0)
memmove(recv_buffer, recv_buffer + to_recv, m_recv_window.data_size);
const size_t nrecv = BAN::Math::min<size_t>(message.msg_iov[i].iov_len, m_recv_window.data_size);
memcpy(message.msg_iov[i].iov_base, recv_buffer, nrecv);
return to_recv;
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
memmove(recv_buffer, recv_buffer + nrecv, m_recv_window.data_size);
}
BAN::ErrorOr<size_t> TCPSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len)
{
(void)address;
(void)address_len;
return total_recv;
}
BAN::ErrorOr<size_t> TCPSocket::sendmsg_impl(const msghdr& message, int flags)
{
if (flags & MSG_NOSIGNAL)
dwarnln("sendmsg ignoring MSG_NOSIGNAL");
flags &= (MSG_EOR | MSG_OOB /* | MSG_NOSIGNAL */);
if (flags != 0)
{
dwarnln("TODO: sendmsg with flags 0x{H}", flags);
return BAN::Error::from_errno(ENOTSUP);
}
if (CMSG_FIRSTHDR(&message))
dwarnln("ignoring sendmsg control message");
if (address)
return BAN::Error::from_errno(EISCONN);
if (!m_has_connected)
return BAN::Error::from_errno(ENOTCONN);
@ -232,17 +262,23 @@ namespace Kernel
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
}
const size_t to_send = BAN::Math::min<size_t>(message.size(), m_send_window.buffer->size() - m_send_window.data_size);
size_t total_sent = 0;
for (int i = 0; i < message.msg_iovlen; i++)
{
auto* buffer = reinterpret_cast<uint8_t*>(m_send_window.buffer->vaddr());
memcpy(buffer + m_send_window.data_size, message.data(), to_send);
m_send_window.data_size += to_send;
auto* send_buffer = reinterpret_cast<uint8_t*>(m_send_window.buffer->vaddr());
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);
memcpy(send_buffer + m_send_window.data_size, message.msg_iov[i].iov_base, 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();
return to_send;
return total_sent;
}
BAN::ErrorOr<void> TCPSocket::getpeername_impl(sockaddr* address, socklen_t* address_len)

View File

@ -79,6 +79,15 @@ namespace Kernel
m_packet_thread_blocker.unblock();
}
BAN::ErrorOr<void> UDPSocket::connect_impl(const sockaddr* address, socklen_t address_len)
{
if (address_len > static_cast<socklen_t>(sizeof(m_peer_address)))
address_len = sizeof(m_peer_address);
memcpy(&m_peer_address, address, address_len);
m_peer_address_len = address_len;
return {};
}
BAN::ErrorOr<void> UDPSocket::bind_impl(const sockaddr* address, socklen_t address_len)
{
if (is_bound())
@ -86,8 +95,21 @@ namespace Kernel
return m_network_layer.bind_socket_to_address(this, address, address_len);
}
BAN::ErrorOr<size_t> UDPSocket::recvfrom_impl(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len)
BAN::ErrorOr<size_t> UDPSocket::recvmsg_impl(msghdr& message, int flags)
{
flags &= (MSG_OOB | MSG_PEEK | MSG_WAITALL);
if (flags != 0)
{
dwarnln("TODO: recvmsg with flags 0x{H}", flags);
return BAN::Error::from_errno(ENOTSUP);
}
if (CMSG_FIRSTHDR(&message))
{
dwarnln("ignoring recvmsg control message");
message.msg_controllen = 0;
}
if (!is_bound())
{
dprintln("No interface bound");
@ -106,14 +128,21 @@ namespace Kernel
auto packet_info = m_packets.front();
m_packets.pop();
size_t nread = BAN::Math::min<size_t>(packet_info.packet_size, buffer.size());
auto* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr());
message.msg_flags = 0;
size_t total_recv = 0;
for (int i = 0; i < message.msg_iovlen; i++)
{
const size_t nrecv = BAN::Math::min<size_t>(message.msg_iov[i].iov_len, packet_info.packet_size - total_recv);
memcpy(message.msg_iov[i].iov_base, packet_buffer + total_recv, nrecv);
total_recv += nrecv;
if (nrecv < packet_info.packet_size)
message.msg_flags |= MSG_TRUNC;
}
uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr());
memcpy(
buffer.data(),
packet_buffer,
nread
);
memmove(
packet_buffer,
packet_buffer + packet_info.packet_size,
@ -122,21 +151,67 @@ namespace Kernel
m_packet_total_size -= packet_info.packet_size;
if (address && address_len)
if (message.msg_name && message.msg_namelen)
{
if (*address_len > (socklen_t)sizeof(sockaddr_storage))
*address_len = sizeof(sockaddr_storage);
memcpy(address, &packet_info.sender, *address_len);
const size_t namelen = BAN::Math::min<size_t>(message.msg_namelen, sizeof(sockaddr_storage));
memcpy(message.msg_name, &packet_info.sender, namelen);
message.msg_namelen = namelen;
}
return nread;
return total_recv;
}
BAN::ErrorOr<size_t> UDPSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len)
BAN::ErrorOr<size_t> UDPSocket::sendmsg_impl(const msghdr& message, int flags)
{
if (flags & MSG_NOSIGNAL)
dwarnln("sendmsg ignoring MSG_NOSIGNAL");
flags &= (MSG_EOR | MSG_OOB /* | MSG_NOSIGNAL */);
if (flags != 0)
{
dwarnln("TODO: sendmsg with flags 0x{H}", flags);
return BAN::Error::from_errno(ENOTSUP);
}
if (CMSG_FIRSTHDR(&message))
dwarnln("ignoring sendmsg control message");
if (!is_bound())
TRY(m_network_layer.bind_socket_to_unused(this, address, address_len));
return TRY(m_network_layer.sendto(*this, message, address, address_len));
TRY(m_network_layer.bind_socket_to_unused(this, static_cast<sockaddr*>(message.msg_name), message.msg_namelen));
const size_t total_send_size =
[&message]() -> size_t {
size_t result = 0;
for (int i = 0; i < message.msg_iovlen; i++)
result += message.msg_iov[i].iov_len;
return result;
}();
BAN::Vector<uint8_t> buffer;
TRY(buffer.resize(total_send_size));
size_t offset = 0;
for (int i = 0; i < message.msg_iovlen; i++)
{
memcpy(buffer.data() + offset, message.msg_iov[i].iov_base, message.msg_iov[i].iov_len);
offset += message.msg_iov[i].iov_len;
}
sockaddr* address;
socklen_t address_len;
if (!message.msg_name || message.msg_namelen == 0)
{
if (m_peer_address_len == 0)
return BAN::Error::from_errno(EDESTADDRREQ);
address = reinterpret_cast<sockaddr*>(&m_peer_address);
address_len = m_peer_address_len;
}
else
{
address = static_cast<sockaddr*>(message.msg_name);
address_len = message.msg_namelen;
}
return TRY(m_network_layer.sendto(*this, buffer.span(), address, address_len));
}
BAN::ErrorOr<long> UDPSocket::ioctl_impl(int request, void* argument)

View File

@ -1,6 +1,7 @@
#include <BAN/HashMap.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Networking/NetworkManager.h>
#include <kernel/Networking/UNIX/Socket.h>
#include <kernel/Process.h>
@ -22,10 +23,28 @@ namespace Kernel
};
static BAN::HashMap<BAN::RefPtr<Inode>, BAN::WeakPtr<UnixDomainSocket>, UnixSocketHash> s_bound_sockets;
static SpinLock s_bound_socket_lock;
static Mutex s_bound_socket_lock;
static constexpr size_t s_packet_buffer_size = 10 * PAGE_SIZE;
static BAN::ErrorOr<BAN::StringView> validate_sockaddr_un(const sockaddr* address, socklen_t address_len)
{
if (address_len < static_cast<socklen_t>(sizeof(sa_family_t)))
return BAN::Error::from_errno(EINVAL);
if (address_len > static_cast<socklen_t>(sizeof(sockaddr_un)))
address_len = sizeof(sockaddr_un);
const auto& sockaddr_un = *reinterpret_cast<const struct sockaddr_un*>(address);
if (sockaddr_un.sun_family != AF_UNIX)
return BAN::Error::from_errno(EINVAL);
size_t length = 0;
while (length < address_len - sizeof(sa_family_t) && sockaddr_un.sun_path[length])
length++;
return BAN::StringView { sockaddr_un.sun_path, length };
}
// FIXME: why is this using spinlocks instead of mutexes??
BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> UnixDomainSocket::create(Socket::Type socket_type, const Socket::Info& info)
@ -64,7 +83,7 @@ namespace Kernel
{
if (is_bound() && !is_bound_to_unused())
{
SpinLockGuard _(s_bound_socket_lock);
LockGuard _(s_bound_socket_lock);
s_bound_sockets.remove(m_bound_file.inode);
}
if (m_info.has<ConnectionInfo>())
@ -105,11 +124,9 @@ namespace Kernel
BAN::RefPtr<UnixDomainSocket> pending;
{
SpinLockGuard guard(connection_info.pending_lock);
SpinLockGuardAsMutex smutex(guard);
LockGuard _(connection_info.pending_lock);
while (connection_info.pending_connections.empty())
TRY(Thread::current().block_or_eintr_indefinite(connection_info.pending_thread_blocker, &smutex));
TRY(Thread::current().block_or_eintr_indefinite(connection_info.pending_thread_blocker, &connection_info.pending_lock));
pending = connection_info.pending_connections.front();
connection_info.pending_connections.pop();
@ -146,15 +163,11 @@ namespace Kernel
BAN::ErrorOr<void> UnixDomainSocket::connect_impl(const sockaddr* address, socklen_t address_len)
{
if (address_len != sizeof(sockaddr_un))
return BAN::Error::from_errno(EINVAL);
auto& sockaddr_un = *reinterpret_cast<const struct sockaddr_un*>(address);
if (sockaddr_un.sun_family != AF_UNIX)
return BAN::Error::from_errno(EAFNOSUPPORT);
const auto sun_path = TRY(validate_sockaddr_un(address, address_len));
if (!is_bound())
TRY(m_bound_file.canonical_path.push_back('X'));
auto absolute_path = TRY(Process::current().absolute_path_of(sockaddr_un.sun_path));
auto absolute_path = TRY(Process::current().absolute_path_of(sun_path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(
Process::current().root_file().inode,
Process::current().credentials(),
@ -165,7 +178,7 @@ namespace Kernel
BAN::RefPtr<UnixDomainSocket> target;
{
SpinLockGuard _(s_bound_socket_lock);
LockGuard _(s_bound_socket_lock);
auto it = s_bound_sockets.find(file.inode);
if (it == s_bound_sockets.end())
return BAN::Error::from_errno(ECONNREFUSED);
@ -196,7 +209,7 @@ namespace Kernel
{
auto& target_info = target->m_info.get<ConnectionInfo>();
SpinLockGuard guard(target_info.pending_lock);
LockGuard _(target_info.pending_lock);
if (target_info.pending_connections.size() < target_info.pending_connections.capacity())
{
@ -205,8 +218,7 @@ namespace Kernel
break;
}
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(target_info.pending_thread_blocker, &smutex));
TRY(Thread::current().block_or_eintr_indefinite(target_info.pending_thread_blocker, &target_info.pending_lock));
}
target->epoll_notify(EPOLLIN);
@ -236,21 +248,16 @@ namespace Kernel
{
if (is_bound())
return BAN::Error::from_errno(EINVAL);
if (address_len != sizeof(sockaddr_un))
return BAN::Error::from_errno(EINVAL);
auto& sockaddr_un = *reinterpret_cast<const struct sockaddr_un*>(address);
if (sockaddr_un.sun_family != AF_UNIX)
return BAN::Error::from_errno(EAFNOSUPPORT);
auto bind_path = BAN::StringView(sockaddr_un.sun_path);
if (bind_path.empty())
const auto sun_path = TRY(validate_sockaddr_un(address, address_len));
if (sun_path.empty())
return BAN::Error::from_errno(EINVAL);
// FIXME: This feels sketchy
auto parent_file = bind_path.front() == '/'
auto parent_file = sun_path.front() == '/'
? TRY(Process::current().root_file().clone())
: TRY(Process::current().working_directory().clone());
if (auto ret = Process::current().create_file_or_dir(AT_FDCWD, bind_path.data(), 0755 | S_IFSOCK); ret.is_error())
if (auto ret = Process::current().create_file_or_dir(AT_FDCWD, sun_path.data(), 0755 | S_IFSOCK); ret.is_error())
{
if (ret.error().get_error_code() == EEXIST)
return BAN::Error::from_errno(EADDRINUSE);
@ -260,11 +267,11 @@ namespace Kernel
Process::current().root_file().inode,
parent_file,
Process::current().credentials(),
bind_path,
sun_path,
O_RDWR
));
SpinLockGuard _(s_bound_socket_lock);
LockGuard _(s_bound_socket_lock);
if (s_bound_sockets.contains(file.inode))
return BAN::Error::from_errno(EADDRINUSE);
TRY(s_bound_sockets.emplace(file.inode, TRY(get_weak_ptr())));
@ -287,21 +294,25 @@ namespace Kernel
}
}
BAN::ErrorOr<void> UnixDomainSocket::add_packet(BAN::ConstByteSpan packet)
BAN::ErrorOr<void> UnixDomainSocket::add_packet(const msghdr& packet, PacketInfo&& packet_info)
{
SpinLockGuard guard(m_packet_lock);
while (m_packet_sizes.full() || m_packet_size_total + packet.size() > s_packet_buffer_size)
{
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &smutex));
}
LockGuard _(m_packet_lock);
while (m_packet_infos.full() || m_packet_size_total + packet_info.size > s_packet_buffer_size)
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &m_packet_lock));
uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr() + m_packet_size_total);
memcpy(packet_buffer, packet.data(), packet.size());
m_packet_size_total += packet.size();
if (!is_streaming())
m_packet_sizes.push(packet.size());
size_t offset = 0;
for (int i = 0; i < packet.msg_iovlen; i++)
{
memcpy(packet_buffer + offset, packet.msg_iov[i].iov_base, packet.msg_iov[i].iov_len);
offset += packet.msg_iov[i].iov_len;
}
ASSERT(offset == packet_info.size);
m_packet_size_total += packet_info.size;
m_packet_infos.emplace(BAN::move(packet_info));
m_packet_thread_blocker.unblock();
@ -315,10 +326,10 @@ namespace Kernel
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
if (connection_info.listening)
return !connection_info.pending_connections.empty();
if (connection_info.target_closed)
return true;
if (!connection_info.pending_connections.empty())
return true;
if (!connection_info.connection)
return false;
}
@ -331,7 +342,13 @@ namespace Kernel
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
return connection_info.connection.valid();
auto connection = connection_info.connection.lock();
if (!connection)
return false;
if (connection->m_packet_infos.full())
return false;
if (connection->m_packet_size_total >= s_packet_buffer_size)
return false;
}
return true;
@ -348,27 +365,257 @@ namespace Kernel
return false;
}
BAN::ErrorOr<size_t> UnixDomainSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len)
BAN::ErrorOr<size_t> UnixDomainSocket::recvmsg_impl(msghdr& message, int flags)
{
if (message.size() > s_packet_buffer_size)
flags &= (MSG_OOB | MSG_PEEK | MSG_WAITALL);
if (flags != 0)
{
dwarnln("TODO: recvmsg with flags 0x{H}", flags);
return BAN::Error::from_errno(ENOTSUP);
}
LockGuard _(m_packet_lock);
while (m_packet_size_total == 0)
{
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
bool expected = true;
if (connection_info.target_closed.compare_exchange(expected, false))
return 0;
if (!connection_info.connection)
return BAN::Error::from_errno(ENOTCONN);
}
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &m_packet_lock));
}
auto* cheader = CMSG_FIRSTHDR(&message);
if (cheader != nullptr)
cheader->cmsg_len = message.msg_controllen;
size_t cheader_len = 0;
uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr());
message.msg_flags = 0;
int iov_index = 0;
size_t iov_offset = 0;
size_t total_recv = 0;
while (!m_packet_infos.empty() && iov_index < message.msg_iovlen)
{
auto& packet_info = m_packet_infos.front();
auto fds_to_open = BAN::move(packet_info.fds);
auto ucred_to_recv = BAN::move(packet_info.ucred);
const bool had_ancillary_data = !fds_to_open.empty() || ucred_to_recv.has_value();
if (!fds_to_open.empty()) do
{
if (cheader == nullptr)
{
dwarnln("no space to receive {} fds", fds_to_open.size());
message.msg_flags |= MSG_CTRUNC;
break;
}
const size_t max_fd_count = (cheader->cmsg_len - sizeof(cmsghdr)) / sizeof(int);
if (max_fd_count < fds_to_open.size())
message.msg_flags |= MSG_CTRUNC;
const size_t fd_count = BAN::Math::min(fds_to_open.size(), max_fd_count);
const size_t fds_opened = Process::current().open_file_descriptor_set().open_all_fd_wrappers(fds_to_open.span().slice(0, fd_count));
auto* fd_data = reinterpret_cast<int*>(CMSG_DATA(cheader));
for (size_t i = 0; i < fds_opened; i++)
fd_data[i] = fds_to_open[i].fd();
const size_t header_length = CMSG_LEN(fds_opened * sizeof(int));
cheader->cmsg_level = SOL_SOCKET;
cheader->cmsg_type = SCM_RIGHTS;
cheader->cmsg_len = header_length;
cheader = CMSG_NXTHDR(&message, cheader);
if (cheader != nullptr)
cheader->cmsg_len = message.msg_controllen - header_length;
cheader_len += header_length;
} while (false);
if (ucred_to_recv.has_value()) do
{
if (cheader == nullptr || cheader->cmsg_len - sizeof(cmsghdr) < sizeof(struct ucred))
{
dwarnln("no space to receive credentials");
message.msg_flags |= MSG_CTRUNC;
break;
}
*reinterpret_cast<struct ucred*>(CMSG_DATA(cheader)) = ucred_to_recv.value();
const size_t header_length = CMSG_LEN(sizeof(struct ucred));
cheader->cmsg_level = SOL_SOCKET;
cheader->cmsg_type = SCM_CREDENTIALS;
cheader->cmsg_len = header_length;
cheader = CMSG_NXTHDR(&message, cheader);
if (cheader != nullptr)
cheader->cmsg_len = message.msg_controllen - header_length;
cheader_len += header_length;
} while (false);
size_t packet_received = 0;
while (iov_index < message.msg_iovlen && packet_received < packet_info.size)
{
auto& iov = message.msg_iov[iov_index];
uint8_t* iov_base = static_cast<uint8_t*>(iov.iov_base);
const size_t nrecv = BAN::Math::min<size_t>(iov.iov_len - iov_offset, packet_info.size - packet_received);
memcpy(iov_base + iov_offset, packet_buffer + packet_received, nrecv);
packet_received += nrecv;
iov_offset += nrecv;
if (iov_offset >= iov.iov_len)
{
iov_offset = 0;
iov_index++;
}
}
if (!is_streaming() && packet_received < packet_info.size)
message.msg_flags |= MSG_TRUNC;
const size_t to_discard = is_streaming() ? packet_received : packet_info.size;
packet_info.size -= to_discard;
if (packet_info.size == 0)
m_packet_infos.pop();
// FIXME: get rid of this memmove :)
memmove(packet_buffer, packet_buffer + to_discard, m_packet_size_total - to_discard);
m_packet_size_total -= to_discard;
total_recv += packet_received;
// on linux ancillary data is a barrier on stream sockets, lets do the same
if (!is_streaming() || had_ancillary_data)
break;
}
message.msg_controllen = cheader_len;
m_packet_thread_blocker.unblock();
epoll_notify(EPOLLOUT);
return total_recv;
}
BAN::ErrorOr<size_t> UnixDomainSocket::sendmsg_impl(const msghdr& message, int flags)
{
if (flags & MSG_NOSIGNAL)
dwarnln("sendmsg ignoring MSG_NOSIGNAL");
flags &= (MSG_EOR | MSG_OOB /* | MSG_NOSIGNAL */);
if (flags != 0)
{
dwarnln("TODO: sendmsg with flags 0x{H}", flags);
return BAN::Error::from_errno(ENOTSUP);
}
const size_t total_message_size =
[&message]() -> size_t {
size_t result = 0;
for (int i = 0; i < message.msg_iovlen; i++)
result += message.msg_iov[i].iov_len;
return result;
}();
if (total_message_size > s_packet_buffer_size)
return BAN::Error::from_errno(ENOBUFS);
PacketInfo packet_info {
.size = total_message_size,
.fds = {},
.ucred = {},
};
for (const auto* header = CMSG_FIRSTHDR(&message); header; header = CMSG_NXTHDR(&message, header))
{
if (header->cmsg_level != SOL_SOCKET)
{
dwarnln("ignoring control message with level {}", header->cmsg_level);
continue;
}
switch (header->cmsg_type)
{
case SCM_RIGHTS:
{
if (!packet_info.fds.empty())
{
dwarnln("multiple SCM_RIGHTS in one sendmsg");
return BAN::Error::from_errno(EINVAL);
}
const auto* fd_data = reinterpret_cast<const int*>(CMSG_DATA(header));
const size_t fd_count = (header->cmsg_len - sizeof(cmsghdr)) / sizeof(int);
for (size_t i = 0; i < fd_count; i++)
TRY(packet_info.fds.push_back(TRY(Process::current().open_file_descriptor_set().get_fd_wrapper(fd_data[i]))));
break;
}
case SCM_CREDENTIALS:
{
if (packet_info.ucred.has_value())
{
dwarnln("multiple SCM_CREDENTIALS in one sendmsg");
return BAN::Error::from_errno(EINVAL);
}
if (header->cmsg_len - sizeof(cmsghdr) < sizeof(struct ucred))
return BAN::Error::from_errno(EINVAL);
const ucred* ucred = reinterpret_cast<const struct ucred*>(CMSG_DATA(header));
const bool is_valid_ucred =
[ucred]() -> bool
{
const auto& creds = Process::current().credentials();
if (creds.is_superuser())
return true;
if (ucred->pid != Process::current().pid())
return false;
if (ucred->uid != creds.ruid() && ucred->uid != creds.euid() && ucred->uid != creds.suid())
return false;
if (ucred->gid != creds.rgid() && !creds.has_egid(ucred->gid) && ucred->gid != creds.sgid())
return false;
return true;
}();
if (!is_valid_ucred)
return BAN::Error::from_errno(EPERM);
packet_info.ucred = *ucred;
break;
}
default:
dwarnln("ignoring control message with type {}", header->cmsg_type);
break;
}
}
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
if (address)
return BAN::Error::from_errno(EISCONN);
auto target = connection_info.connection.lock();
if (!target)
return BAN::Error::from_errno(ENOTCONN);
TRY(target->add_packet(message));
return message.size();
TRY(target->add_packet(message, BAN::move(packet_info)));
return total_message_size;
}
else
{
BAN::RefPtr<Inode> target_inode;
if (!address)
if (!message.msg_name || message.msg_namelen == 0)
{
auto& connectionless_info = m_info.get<ConnectionlessInfo>();
if (connectionless_info.peer_address.empty())
@ -384,13 +631,8 @@ namespace Kernel
}
else
{
if (address_len != sizeof(sockaddr_un))
return BAN::Error::from_errno(EINVAL);
auto& sockaddr_un = *reinterpret_cast<const struct sockaddr_un*>(address);
if (sockaddr_un.sun_family != AF_UNIX)
return BAN::Error::from_errno(EAFNOSUPPORT);
auto absolute_path = TRY(Process::current().absolute_path_of(sockaddr_un.sun_path));
const auto sun_path = TRY(validate_sockaddr_un(static_cast<sockaddr*>(message.msg_name), message.msg_namelen));
auto absolute_path = TRY(Process::current().absolute_path_of(sun_path));
target_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(
Process::current().root_file().inode,
Process::current().credentials(),
@ -399,59 +641,23 @@ namespace Kernel
)).inode;
}
SpinLockGuard _(s_bound_socket_lock);
BAN::RefPtr<UnixDomainSocket> target;
{
LockGuard _(s_bound_socket_lock);
auto it = s_bound_sockets.find(target_inode);
if (it == s_bound_sockets.end())
return BAN::Error::from_errno(EDESTADDRREQ);
auto target = it->value.lock();
target = it->value.lock();
}
if (!target)
return BAN::Error::from_errno(EDESTADDRREQ);
TRY(target->add_packet(message));
return message.size();
TRY(target->add_packet(message, BAN::move(packet_info)));
return total_message_size;
}
}
BAN::ErrorOr<size_t> UnixDomainSocket::recvfrom_impl(BAN::ByteSpan buffer, sockaddr*, socklen_t*)
{
SpinLockGuard guard(m_packet_lock);
while (m_packet_size_total == 0)
{
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
bool expected = true;
if (connection_info.target_closed.compare_exchange(expected, false))
return 0;
if (!connection_info.connection)
return BAN::Error::from_errno(ENOTCONN);
}
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &smutex));
}
uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr());
size_t nread = 0;
if (is_streaming())
nread = BAN::Math::min(buffer.size(), m_packet_size_total);
else
{
nread = BAN::Math::min(buffer.size(), m_packet_sizes.front());
m_packet_sizes.pop();
}
memcpy(buffer.data(), packet_buffer, nread);
memmove(packet_buffer, packet_buffer + nread, m_packet_size_total - nread);
m_packet_size_total -= nread;
m_packet_thread_blocker.unblock();
epoll_notify(EPOLLOUT);
return nread;
}
BAN::ErrorOr<void> UnixDomainSocket::getpeername_impl(sockaddr* address, socklen_t* address_len)
{
if (!m_info.has<ConnectionInfo>())

View File

@ -217,7 +217,7 @@ namespace Kernel
return fildes;
}
BAN::ErrorOr<int> OpenFileDescriptorSet::fcntl(int fd, int cmd, int extra)
BAN::ErrorOr<int> OpenFileDescriptorSet::fcntl(int fd, int cmd, uintptr_t extra)
{
LockGuard _(m_mutex);
@ -424,7 +424,24 @@ namespace Kernel
}
if (inode->mode().ifsock())
return recvfrom(fd, buffer, nullptr, nullptr);
{
iovec iov {
.iov_base = buffer.data(),
.iov_len = buffer.size(),
};
msghdr message {
.msg_name = nullptr,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = nullptr,
.msg_controllen = 0,
.msg_flags = 0,
};
return recvmsg(fd, message, 0);
}
size_t nread;
{
@ -461,14 +478,31 @@ namespace Kernel
}
if (inode->mode().ifsock())
return sendto(fd, buffer, nullptr, 0);
{
iovec iov {
.iov_base = const_cast<uint8_t*>(buffer.data()),
.iov_len = buffer.size(),
};
msghdr message {
.msg_name = nullptr,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = nullptr,
.msg_controllen = 0,
.msg_flags = 0,
};
return sendmsg(fd, message, 0);
}
size_t nwrite;
{
LockGuard _(inode->m_mutex);
if (inode->has_error())
{
Thread::current().add_signal(SIGPIPE);
Thread::current().add_signal(SIGPIPE, {});
return BAN::Error::from_errno(EPIPE);
}
if (is_nonblock && !inode->can_write())
@ -515,7 +549,7 @@ namespace Kernel
}
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len)
BAN::ErrorOr<size_t> OpenFileDescriptorSet::recvmsg(int fd, msghdr& message, int flags)
{
BAN::RefPtr<Inode> inode;
bool is_nonblock;
@ -533,10 +567,10 @@ namespace Kernel
LockGuard _(inode->m_mutex);
if (is_nonblock && !inode->can_read())
return BAN::Error::from_errno(EWOULDBLOCK);
return inode->recvfrom(buffer, address, address_len);
return inode->recvmsg(message, flags);
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len)
BAN::ErrorOr<size_t> OpenFileDescriptorSet::sendmsg(int fd, const msghdr& message, int flags)
{
BAN::RefPtr<Inode> inode;
bool is_nonblock;
@ -554,12 +588,12 @@ namespace Kernel
LockGuard _(inode->m_mutex);
if (inode->has_hungup())
{
Thread::current().add_signal(SIGPIPE);
Thread::current().add_signal(SIGPIPE, {});
return BAN::Error::from_errno(EPIPE);
}
if (is_nonblock && !inode->can_write())
return BAN::Error::from_errno(EWOULDBLOCK);
return inode->sendto(buffer, address, address_len);
return inode->sendmsg(message, flags);
}
BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const
@ -625,4 +659,66 @@ namespace Kernel
return BAN::Error::from_errno(EMFILE);
}
using FDWrapper = OpenFileDescriptorSet::FDWrapper;
FDWrapper::FDWrapper(BAN::RefPtr<OpenFileDescription> description)
: m_description(description)
{
if (m_description)
m_description->file.inode->on_clone(m_description->status_flags);
}
FDWrapper::~FDWrapper()
{
clear();
}
FDWrapper& FDWrapper::operator=(const FDWrapper& other)
{
clear();
m_description = other.m_description;
if (m_description)
m_description->file.inode->on_clone(m_description->status_flags);
return *this;
}
FDWrapper& FDWrapper::operator=(FDWrapper&& other)
{
clear();
m_description = BAN::move(other.m_description);
return *this;
}
void FDWrapper::clear()
{
if (m_description)
m_description->file.inode->on_close(m_description->status_flags);
}
BAN::ErrorOr<FDWrapper> OpenFileDescriptorSet::get_fd_wrapper(int fd)
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
return FDWrapper { m_open_files[fd].description };
}
size_t OpenFileDescriptorSet::open_all_fd_wrappers(BAN::Span<FDWrapper> fd_wrappers)
{
LockGuard _(m_mutex);
for (size_t i = 0; i < fd_wrappers.size(); i++)
{
auto fd_or_error = get_free_fd();
if (fd_or_error.is_error())
return i;
const int fd = fd_or_error.release_value();
m_open_files[fd].description = BAN::move(fd_wrappers[i].m_description);
m_open_files[fd].descriptor_flags = 0;
fd_wrappers[i].m_fd = fd;
}
return fd_wrappers.size();
}
}

View File

@ -161,7 +161,7 @@ namespace Kernel
if (executable.master_tls.has_value())
{
auto tls_result = TRY(process->initialize_thread_local_storage(process->page_table(), *executable.master_tls));
TRY(process->m_mapped_regions.emplace_back(BAN::move(tls_result.region)));
TRY(process->add_mapped_region(BAN::move(tls_result.region)));
tls_addr = tls_result.addr;
}
@ -173,7 +173,15 @@ namespace Kernel
auxiliary_vector.span()
));
if (tls_addr.has_value())
thread->set_tls(*tls_addr);
{
#if ARCH(x86_64)
thread->set_fsbase(*tls_addr);
#elif ARCH(i686)
thread->set_gsbase(*tls_addr);
#else
#error
#endif
}
process->add_thread(thread);
process->register_to_scheduler();
@ -305,7 +313,17 @@ namespace Kernel
child.status = __WGENEXITCODE(status, signal);
parent_process->add_pending_signal(SIGCHLD);
parent_process->add_pending_signal(SIGCHLD, {
.si_signo = SIGCHLD,
.si_code = signal ? CLD_KILLED : CLD_EXITED,
.si_errno = 0,
.si_pid = pid(),
.si_uid = m_credentials.ruid(),
.si_addr = nullptr,
.si_status = __WGENEXITCODE(status, signal),
.si_band = 0,
.si_value = {},
});
if (!parent_process->m_threads.empty())
Processor::scheduler().unblock_thread(parent_process->m_threads.front());
@ -320,7 +338,7 @@ namespace Kernel
LockGuard _(m_process_lock);
for (auto* thread : m_threads)
if (thread != &Thread::current())
thread->add_signal(SIGKILL);
thread->add_signal(SIGKILL, {});
}
while (m_threads.size() > 1)
@ -397,6 +415,33 @@ namespace Kernel
return result;
}
BAN::ErrorOr<void> Process::add_mapped_region(BAN::UniqPtr<MemoryRegion>&& region)
{
const size_t index = find_mapped_region(region->vaddr());
TRY(m_mapped_regions.insert(index, BAN::move(region)));
return {};
}
size_t Process::find_mapped_region(vaddr_t address) const
{
size_t l = 0, r = m_mapped_regions.size();
while (l < r)
{
const size_t mid = (l + r) / 2;
if (m_mapped_regions[mid]->contains(address))
return mid;
if (m_mapped_regions[mid]->vaddr() < address)
l = mid + 1;
else
r = mid;
}
return l;
}
size_t Process::proc_meminfo(off_t offset, BAN::ByteSpan buffer) const
{
ASSERT(offset >= 0);
@ -463,7 +508,15 @@ namespace Kernel
return read_from_vec_of_str(m_environ, offset, buffer);
}
BAN::ErrorOr<BAN::String> Process::proc_executable() const
BAN::ErrorOr<BAN::String> Process::proc_cwd() const
{
LockGuard _(m_process_lock);
BAN::String result;
TRY(result.append(m_working_directory.canonical_path));
return result;
}
BAN::ErrorOr<BAN::String> Process::proc_exe() const
{
LockGuard _(m_process_lock);
BAN::String result;
@ -487,7 +540,7 @@ namespace Kernel
{
ASSERT(m_process_lock.is_locked());
if (path[0] == '\0')
if (path && path[0] == '\0')
return BAN::Error::from_errno(ENOENT);
auto relative_parent = TRY(find_relative_parent(fd, path));
@ -730,7 +783,13 @@ namespace Kernel
{
auto tls_result = TRY(initialize_thread_local_storage(*new_page_table, *executable.master_tls));
TRY(new_mapped_regions.emplace_back(BAN::move(tls_result.region)));
new_thread->set_tls(tls_result.addr);
#if ARCH(x86_64)
new_thread->set_fsbase(tls_result.addr);
#elif ARCH(i686)
new_thread->set_gsbase(tls_result.addr);
#else
#error
#endif
}
// NOTE: this is done before disabling interrupts and moving the threads as
@ -1013,7 +1072,17 @@ namespace Kernel
if (current_ns < process->m_alarm_wake_time_ns)
break;
process->add_pending_signal(SIGALRM);
process->add_pending_signal(SIGALRM, {
.si_signo = SIGALRM,
.si_code = SI_TIMER,
.si_errno = 0,
.si_pid = 0,
.si_uid = 0,
.si_addr = nullptr,
.si_status = 0,
.si_band = 0,
.si_value = {},
});
ASSERT(!process->m_threads.empty());
Processor::scheduler().unblock_thread(process->m_threads.front());
@ -1077,14 +1146,15 @@ namespace Kernel
if (Thread::current().userspace_stack().contains(address))
return Thread::current().userspace_stack().allocate_page_for_demand_paging(address);
for (auto& region : m_mapped_regions)
{
if (!region->contains(address))
continue;
return region->allocate_page_containing(address, wants_write);
}
const size_t index = find_mapped_region(address);
if (index >= m_mapped_regions.size())
return false;
auto& region = m_mapped_regions[index];
if (!region->contains(address))
return false;
return region->allocate_page_containing(address, wants_write);
}
BAN::ErrorOr<long> Process::open_inode(VirtualFileSystem::File&& file, int flags)
@ -1232,6 +1302,27 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_renameat(int oldfd, const char* old, int newfd, const char* _new)
{
LockGuard _(m_process_lock);
if (old != nullptr)
TRY(validate_string_access(old));
if (_new != nullptr)
TRY(validate_string_access(_new));
auto [old_parent, old_name] = TRY(find_parent_file(oldfd, old, O_WRONLY));
if (!old_parent.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
auto [new_parent, new_name] = TRY(find_parent_file(newfd, _new, O_WRONLY));
if (!new_parent.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
TRY(new_parent.inode->rename_inode(old_parent.inode, old_name, new_name));
return 0;
}
BAN::ErrorOr<long> Process::sys_unlinkat(int fd, const char* path, int flag)
{
if (flag && flag != AT_REMOVEDIR)
@ -1243,9 +1334,15 @@ namespace Kernel
auto [parent, file_name] = TRY(find_parent_file(fd, path, O_WRONLY));
if (TRY(parent.inode->find_inode(file_name))->mode().ifdir() != (flag == AT_REMOVEDIR))
const auto inode = TRY(parent.inode->find_inode(file_name));
if (inode->mode().ifdir() != (flag == AT_REMOVEDIR))
return BAN::Error::from_errno(flag ? EPERM : ENOTDIR);
if (parent.inode->mode().mode & Inode::Mode::ISVTX)
if (m_credentials.ruid() != parent.inode->uid() && m_credentials.ruid() != inode->uid())
return BAN::Error::from_errno(EPERM);
TRY(parent.inode->unlink(file_name));
return 0;
@ -1569,73 +1666,72 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_sendto(const sys_sendto_t* _arguments)
BAN::ErrorOr<long> Process::sys_recvmsg(int socket, msghdr* _message, int flags)
{
sys_sendto_t arguments;
msghdr message;
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(_arguments, sizeof(sys_sendto_t), false));
arguments = *_arguments;
TRY(validate_pointer_access(_message, sizeof(msghdr), true));
message = *_message;
}
if (arguments.length == 0)
return BAN::Error::from_errno(EINVAL);
MemoryRegion* message_region = nullptr;
MemoryRegion* address_region = nullptr;
BAN::ScopeGuard _([&] {
if (message_region)
message_region->unpin();
if (address_region)
address_region->unpin();
BAN::Vector<MemoryRegion*> regions;
BAN::ScopeGuard _([&regions] {
for (auto* region : regions)
if (region != nullptr)
region->unpin();
});
message_region = TRY(validate_and_pin_pointer_access(arguments.message, arguments.length, false));
if (arguments.dest_addr)
address_region = TRY(validate_and_pin_pointer_access(arguments.dest_addr, arguments.dest_len, false));
auto message = BAN::ConstByteSpan(static_cast<const uint8_t*>(arguments.message), arguments.length);
return TRY(m_open_file_descriptors.sendto(arguments.socket, message, arguments.dest_addr, arguments.dest_len));
if (message.msg_name)
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_name, message.msg_namelen, true))));
if (message.msg_control)
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_control, message.msg_controllen, true))));
if (message.msg_iov)
{
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_iov, message.msg_iovlen * sizeof(iovec), true))));
for (int i = 0; i < message.msg_iovlen; i++)
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_iov[i].iov_base, message.msg_iov[i].iov_len, true))));
}
BAN::ErrorOr<long> Process::sys_recvfrom(sys_recvfrom_t* _arguments)
{
sys_recvfrom_t arguments;
auto ret = TRY(m_open_file_descriptors.recvmsg(socket, message, flags));
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(_arguments, sizeof(sys_sendto_t), false));
arguments = *_arguments;
TRY(validate_pointer_access(_message, sizeof(msghdr), true));
*_message = message;
}
if (!arguments.address != !arguments.address_len)
return BAN::Error::from_errno(EINVAL);
if (arguments.length == 0)
return BAN::Error::from_errno(EINVAL);
return ret;
}
MemoryRegion* buffer_region = nullptr;
MemoryRegion* address_region1 = nullptr;
MemoryRegion* address_region2 = nullptr;
BAN::ErrorOr<long> Process::sys_sendmsg(int socket, const msghdr* _message, int flags)
{
msghdr message;
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(_message, sizeof(msghdr), false));
message = *_message;
}
BAN::ScopeGuard _([&] {
if (buffer_region)
buffer_region->unpin();
if (address_region1)
address_region1->unpin();
if (address_region2)
address_region2->unpin();
BAN::Vector<MemoryRegion*> regions;
BAN::ScopeGuard _([&regions] {
for (auto* region : regions)
if (region != nullptr)
region->unpin();
});
buffer_region = TRY(validate_and_pin_pointer_access(arguments.buffer, arguments.length, true));
if (arguments.address_len)
if (message.msg_name)
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_name, message.msg_namelen, false))));
if (message.msg_control)
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_control, message.msg_controllen, false))));
if (message.msg_iov)
{
address_region1 = TRY(validate_and_pin_pointer_access(arguments.address_len, sizeof(*arguments.address_len), true));
address_region2 = TRY(validate_and_pin_pointer_access(arguments.address, *arguments.address_len, true));
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_iov, message.msg_iovlen * sizeof(iovec), false))));
for (int i = 0; i < message.msg_iovlen; i++)
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_iov[i].iov_base, message.msg_iov[i].iov_len, false))));
}
auto message = BAN::ByteSpan(static_cast<uint8_t*>(arguments.buffer), arguments.length);
return TRY(m_open_file_descriptors.recvfrom(arguments.socket, message, arguments.address, arguments.address_len));
return TRY(m_open_file_descriptors.sendmsg(socket, message, flags));
}
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg)
@ -1998,7 +2094,7 @@ namespace Kernel
return TRY(m_open_file_descriptors.dup2(fildes, fildes2));
}
BAN::ErrorOr<long> Process::sys_fcntl(int fildes, int cmd, int extra)
BAN::ErrorOr<long> Process::sys_fcntl(int fildes, int cmd, uintptr_t extra)
{
return TRY(m_open_file_descriptors.fcntl(fildes, cmd, extra));
}
@ -2190,6 +2286,38 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<BAN::Vector<BAN::UniqPtr<MemoryRegion>>> Process::split_memory_region(BAN::UniqPtr<MemoryRegion>&& region, vaddr_t base, size_t length)
{
ASSERT(base % PAGE_SIZE == 0);
ASSERT(base < region->vaddr() + region->size());
if (auto rem = length % PAGE_SIZE)
length += PAGE_SIZE - rem;
if (base + length > region->vaddr() + region->size())
length = region->vaddr() + region->size() - base;
BAN::Vector<BAN::UniqPtr<MemoryRegion>> result;
TRY(result.reserve(3));
if (region->vaddr() < base)
{
auto temp = TRY(region->split(base - region->vaddr()));
MUST(result.push_back(BAN::move(region)));
region = BAN::move(temp);
}
if (base + length < region->vaddr() + region->size())
{
auto temp = TRY(region->split(base + length - region->vaddr()));
MUST(result.push_back(BAN::move(region)));
region = BAN::move(temp);
}
MUST(result.push_back(BAN::move(region)));
return result;
}
BAN::ErrorOr<long> Process::sys_mmap(const sys_mmap_t* user_args)
{
sys_mmap_t args;
@ -2202,6 +2330,9 @@ namespace Kernel
if (args.prot != PROT_NONE && (args.prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)))
return BAN::Error::from_errno(EINVAL);
if (!(args.flags & MAP_ANONYMOUS) && (args.off % PAGE_SIZE))
return BAN::Error::from_errno(EINVAL);
if (!(args.flags & MAP_PRIVATE) == !(args.flags & MAP_SHARED))
return BAN::Error::from_errno(EINVAL);
auto region_type = (args.flags & MAP_PRIVATE) ? MemoryRegion::Type::PRIVATE : MemoryRegion::Type::SHARED;
@ -2219,30 +2350,67 @@ namespace Kernel
else
page_flags |= PageTable::Flags::UserSupervisor;
LockGuard _(m_process_lock);
AddressRange address_range { .start = 0x400000, .end = USERSPACE_END };
if (args.flags & MAP_FIXED)
if (args.flags & (MAP_FIXED | MAP_FIXED_NOREPLACE))
{
vaddr_t base_addr = reinterpret_cast<vaddr_t>(args.addr);
address_range.start = BAN::Math::div_round_up<vaddr_t>(base_addr, PAGE_SIZE) * PAGE_SIZE;
address_range.end = BAN::Math::div_round_up<vaddr_t>(base_addr + args.len, PAGE_SIZE) * PAGE_SIZE;
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(args.addr);
if (vaddr == 0 || vaddr % PAGE_SIZE)
return BAN::Error::from_errno(EINVAL);
if (!PageTable::is_valid_pointer(vaddr))
return BAN::Error::from_errno(ENOMEM);
if (!PageTable::is_valid_pointer(vaddr + args.len))
return BAN::Error::from_errno(ENOMEM);
address_range = {
.start = vaddr,
.end = vaddr + args.len,
};
for (size_t i = 0; i < m_mapped_regions.size(); i++)
if (args.flags & MAP_FIXED_NOREPLACE)
;
else
{
if (!m_mapped_regions[i]->overlaps(base_addr, args.len))
continue;
if (!m_mapped_regions[i]->contains_fully(base_addr, args.len))
derrorln("VERY BROKEN MAP_FIXED UNMAP");
const size_t first_index = find_mapped_region(vaddr);
for (size_t i = first_index; i < m_mapped_regions.size(); i++)
{
if (!m_mapped_regions[i]->overlaps(vaddr, args.len))
break;
m_mapped_regions[i]->wait_not_pinned();
auto temp = BAN::move(m_mapped_regions[i]);
m_mapped_regions.remove(i--);
}
if (temp->is_contained_by(vaddr, args.len))
continue;
auto new_regions = TRY(split_memory_region(BAN::move(temp), vaddr, args.len));
for (auto& new_region : new_regions)
if (!new_region->overlaps(vaddr, args.len))
TRY(m_mapped_regions.insert(++i, BAN::move(new_region)));
}
}
}
else if (const vaddr_t vaddr = reinterpret_cast<vaddr_t>(args.addr); vaddr == 0)
;
else if (vaddr % PAGE_SIZE)
;
else if (!PageTable::is_valid_pointer(vaddr))
;
else if (!PageTable::is_valid_pointer(vaddr + args.len))
;
else if (!page_table().is_range_free(vaddr, args.len))
;
else
{
address_range = {
.start = vaddr,
.end = vaddr + args.len,
};
}
if (args.flags & MAP_ANONYMOUS)
{
if (args.off != 0)
return BAN::Error::from_errno(EINVAL);
auto region = TRY(MemoryBackedRegion::create(
page_table(),
args.len,
@ -2251,13 +2419,11 @@ namespace Kernel
O_EXEC | O_RDWR
));
LockGuard _(m_process_lock);
TRY(m_mapped_regions.push_back(BAN::move(region)));
return m_mapped_regions.back()->vaddr();
const vaddr_t region_vaddr = region->vaddr();
TRY(add_mapped_region(BAN::move(region)));
return region_vaddr;
}
LockGuard _(m_process_lock);
auto inode = TRY(m_open_file_descriptors.inode_of(args.fildes));
const auto status_flags = TRY(m_open_file_descriptors.status_flags_of(args.fildes));
@ -2267,10 +2433,10 @@ namespace Kernel
if ((args.prot & PROT_WRITE) && !(status_flags & O_WRONLY))
return BAN::Error::from_errno(EACCES);
BAN::UniqPtr<MemoryRegion> memory_region;
BAN::UniqPtr<MemoryRegion> region;
if (inode->mode().ifreg())
{
memory_region = TRY(FileBackedRegion::create(
region = TRY(FileBackedRegion::create(
inode,
page_table(),
args.off, args.len,
@ -2281,7 +2447,7 @@ namespace Kernel
}
else if (inode->is_device())
{
memory_region = TRY(static_cast<Device&>(*inode).mmap_region(
region = TRY(static_cast<Device&>(*inode).mmap_region(
page_table(),
args.off, args.len,
address_range,
@ -2290,11 +2456,12 @@ namespace Kernel
));
}
if (!memory_region)
if (!region)
return BAN::Error::from_errno(ENODEV);
TRY(m_mapped_regions.push_back(BAN::move(memory_region)));
return m_mapped_regions.back()->vaddr();
const vaddr_t region_vaddr = region->vaddr();
TRY(add_mapped_region(BAN::move(region)));
return region_vaddr;
}
BAN::ErrorOr<long> Process::sys_munmap(void* addr, size_t len)
@ -2302,31 +2469,35 @@ namespace Kernel
if (len == 0)
return BAN::Error::from_errno(EINVAL);
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(addr);
if (vaddr % PAGE_SIZE != 0)
return BAN::Error::from_errno(EINVAL);
vaddr_t vaddr = reinterpret_cast<vaddr_t>(addr);
if (auto rem = vaddr % PAGE_SIZE)
{
vaddr -= rem;
len += rem;
}
if (auto rem = len % PAGE_SIZE)
len += PAGE_SIZE - rem;
LockGuard _(m_process_lock);
// FIXME: We should unmap partial regions.
// This is a hack to only unmap if the whole mmap region
// is contained within [addr, addr + len]
for (size_t i = 0; i < m_mapped_regions.size(); i++)
const size_t first_index = find_mapped_region(vaddr);
for (size_t i = first_index; i < m_mapped_regions.size(); i++)
{
auto& region = m_mapped_regions[i];
if (!m_mapped_regions[i]->overlaps(vaddr, len))
break;
const vaddr_t region_s = region->vaddr();
const vaddr_t region_e = region->vaddr() + region->size();
if (vaddr <= region_s && region_e <= vaddr + len)
{
region->wait_not_pinned();
m_mapped_regions[i]->wait_not_pinned();
auto temp = BAN::move(m_mapped_regions[i]);
m_mapped_regions.remove(i--);
}
else if (region->overlaps(vaddr, len))
dwarnln("TODO: partial region munmap");
if (temp->is_contained_by(vaddr, len))
continue;
auto new_regions = TRY(split_memory_region(BAN::move(temp), vaddr, len));
for (auto& new_region : new_regions)
if (!new_region->overlaps(vaddr, len))
TRY(m_mapped_regions.insert(++i, BAN::move(new_region)));
}
return 0;
@ -2359,39 +2530,36 @@ namespace Kernel
LockGuard _(m_process_lock);
// FIXME: We should protect partial regions.
// This is a hack to only protect if the whole mmap region
// is contained within [addr, addr + len]
for (size_t i = 0; i < m_mapped_regions.size(); i++)
const size_t first_index = find_mapped_region(vaddr);
for (size_t i = first_index; i < m_mapped_regions.size(); i++)
{
if (!m_mapped_regions[i]->overlaps(vaddr, len))
break;
if (!m_mapped_regions[i]->is_contained_by(vaddr, len))
{
m_mapped_regions[i]->wait_not_pinned();
auto temp = BAN::move(m_mapped_regions[i]);
m_mapped_regions.remove(i--);
auto new_regions = TRY(split_memory_region(BAN::move(temp), vaddr, len));
for (size_t j = 0; j < new_regions.size(); j++)
TRY(m_mapped_regions.insert(i + j + 1, BAN::move(new_regions[j])));
continue;
}
auto& region = m_mapped_regions[i];
const vaddr_t region_s = region->vaddr();
const vaddr_t region_e = region->vaddr() + region->size();
if (vaddr <= region_s && region_e <= vaddr + len)
{
const bool is_shared = (region->type() == MemoryRegion::Type::SHARED);
const bool is_writable = (region->status_flags() & O_WRONLY);
const bool want_write = (prot & PROT_WRITE);
if (is_shared && want_write && !is_writable)
return BAN::Error::from_errno(EACCES);
// FIXME: if the region is pinned writable, this may
// cause some problems :D
// NOTE: don't change protection of regions in use
region->wait_not_pinned();
TRY(region->mprotect(flags));
}
else if (region->overlaps(vaddr, len))
{
const bool is_shared = (region->type() == MemoryRegion::Type::SHARED);
const bool is_writable = (region->status_flags() & O_WRONLY);
const bool want_write = (prot & PROT_WRITE);
if (is_shared && want_write && !is_writable)
return BAN::Error::from_errno(EACCES);
dwarnln("TODO: partial region mprotect");
TRY(region->mprotect(flags | region->flags()));
}
}
return 0;
}
@ -2404,9 +2572,16 @@ namespace Kernel
LockGuard _(m_process_lock);
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(addr);
for (auto& mapped_region : m_mapped_regions)
if (mapped_region->overlaps(vaddr, len))
TRY(mapped_region->msync(vaddr, len, flags));
const size_t first_index = find_mapped_region(vaddr);
for (size_t i = first_index; i < m_mapped_regions.size(); i++)
{
auto& region = *m_mapped_regions[i];
if (vaddr >= region.vaddr() + region.size())
break;
if (region.overlaps(vaddr, len))
TRY(region.msync(vaddr, len, flags));
}
return 0;
}
@ -2448,8 +2623,9 @@ namespace Kernel
auto region = TRY(SharedMemoryObjectManager::get().map_object(key, page_table(), { .start = 0x400000, .end = USERSPACE_END }));
LockGuard _(m_process_lock);
TRY(m_mapped_regions.push_back(BAN::move(region)));
return m_mapped_regions.back()->vaddr();
const vaddr_t region_vaddr = region->vaddr();
TRY(add_mapped_region(BAN::move(region)));
return region_vaddr;
}
BAN::ErrorOr<long> Process::sys_ttyname(int fildes, char* name, size_t namesize)
@ -2644,7 +2820,18 @@ namespace Kernel
if (!(m_signal_handlers[SIGCHLD].sa_flags & SA_NOCLDSTOP))
{
parent->add_pending_signal(SIGCHLD);
parent->add_pending_signal(SIGCHLD, {
.si_signo = SIGCHLD,
.si_code = stopped ? CLD_STOPPED : CLD_CONTINUED,
.si_errno = 0,
.si_pid = pid(),
.si_uid = m_credentials.ruid(),
.si_addr = nullptr,
.si_status = __WGENEXITCODE(0, signal),
.si_band = 0,
.si_value = { .sival_int = 0 },
});
if (!parent->m_threads.empty())
Processor::scheduler().unblock_thread(parent->m_threads.front());
}
@ -2670,7 +2857,7 @@ namespace Kernel
}
}
BAN::ErrorOr<void> Process::kill(pid_t pid, int signal)
BAN::ErrorOr<void> Process::kill(pid_t pid, int signal, const siginfo_t& signal_info)
{
if (pid == 0 || pid == -1)
return BAN::Error::from_errno(ENOTSUP);
@ -2694,7 +2881,7 @@ namespace Kernel
process.set_stopped(false, signal);
else
{
process.add_pending_signal(signal);
process.add_pending_signal(signal, signal_info);
if (!process.m_threads.empty())
Processor::scheduler().unblock_thread(process.m_threads.front());
process.m_stop_blocker.unblock();
@ -2716,6 +2903,18 @@ namespace Kernel
if (signal != 0 && (signal < _SIGMIN || signal > _SIGMAX))
return BAN::Error::from_errno(EINVAL);
const siginfo_t signal_info {
.si_signo = signal,
.si_code = SI_USER,
.si_errno = 0,
.si_pid = this->pid(),
.si_uid = m_credentials.ruid(),
.si_addr = nullptr,
.si_status = 0,
.si_band = 0,
.si_value = {},
};
if (pid == m_pid)
{
if (signal == 0)
@ -2726,13 +2925,13 @@ namespace Kernel
set_stopped(false, signal);
else
{
add_pending_signal(signal);
add_pending_signal(signal, signal_info);
m_stop_blocker.unblock();
}
return 0;
}
TRY(kill(pid, signal));
TRY(kill(pid, signal, signal_info));
return 0;
}
@ -2953,16 +3152,28 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_set_tls(void* addr)
BAN::ErrorOr<long> Process::sys_set_fsbase(void* addr)
{
Thread::current().set_tls(reinterpret_cast<vaddr_t>(addr));
Processor::load_tls();
Thread::current().set_fsbase(reinterpret_cast<vaddr_t>(addr));
Processor::load_fsbase();
return 0;
}
BAN::ErrorOr<long> Process::sys_get_tls()
BAN::ErrorOr<long> Process::sys_get_fsbase()
{
return Thread::current().get_tls();
return Thread::current().get_fsbase();
}
BAN::ErrorOr<long> Process::sys_set_gsbase(void* addr)
{
Thread::current().set_gsbase(reinterpret_cast<vaddr_t>(addr));
Processor::load_gsbase();
return 0;
}
BAN::ErrorOr<long> Process::sys_get_gsbase()
{
return Thread::current().get_gsbase();
}
BAN::ErrorOr<long> Process::sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg)
@ -3063,8 +3274,19 @@ namespace Kernel
{
if (thread->tid() != tid)
continue;
if (signal != 0)
thread->add_signal(signal);
if (signal == 0)
return 0;
thread->add_signal(signal, {
.si_signo = signal,
.si_code = SI_USER,
.si_errno = 0,
.si_pid = pid(),
.si_uid = m_credentials.ruid(),
.si_addr = nullptr,
.si_status = 0,
.si_band = 0,
.si_value = {},
});
return 0;
}
@ -3474,62 +3696,64 @@ namespace Kernel
return validate_pointer_access(str, strlen(str) + 1, false);
}
BAN::ErrorOr<void> Process::validate_pointer_access_check(const void* ptr, size_t size, bool needs_write)
{
ASSERT(&Process::current() == this);
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(ptr);
// NOTE: detect overflow
if (vaddr + size < vaddr)
goto unauthorized_access;
// trying to access kernel space memory
if (vaddr + size > USERSPACE_END)
goto unauthorized_access;
for (const auto* thread : m_threads)
if (vaddr >= thread->userspace_stack_bottom() && vaddr + size <= thread->userspace_stack_top())
return {};
// FIXME: should we allow cross mapping access?
for (const auto& mapped_region : m_mapped_regions)
{
if (!mapped_region->contains_fully(vaddr, size))
continue;
if (needs_write && !mapped_region->writable())
goto unauthorized_access;
return {};
}
unauthorized_access:
dwarnln("process {}, thread {} attempted to make an invalid pointer access to 0x{H}->0x{H}", pid(), Thread::current().tid(), vaddr, vaddr + size);
Debug::dump_stack_trace();
MUST(sys_kill(pid(), SIGSEGV));
return BAN::Error::from_errno(EINTR);
}
BAN::ErrorOr<void> Process::validate_pointer_access(const void* ptr, size_t size, bool needs_write)
{
// TODO: This seems very slow as we loop over the range twice
if (size == 0)
return {};
TRY(validate_pointer_access_check(ptr, size, needs_write));
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(ptr);
const auto page_flags = (needs_write ? PageTable::Flags::ReadWrite : 0) | PageTable::Flags::Present;
// Make sure all of the pages are mapped here, so demand paging does not happen
// while processing syscall.
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(ptr);
const vaddr_t page_start = vaddr & PAGE_ADDR_MASK;
const size_t page_count = range_page_count(vaddr, size);
for (size_t i = 0; i < page_count; i++)
{
const vaddr_t current = page_start + i * PAGE_SIZE;
if (page_table().get_page_flags(current) & PageTable::Flags::Present)
if ((page_table().get_page_flags(current) & page_flags) == page_flags)
continue;
TRY(Process::allocate_page_for_demand_paging(current, needs_write, false));
if (!TRY(Process::allocate_page_for_demand_paging(current, needs_write, false)))
{
const MemoryRegion* region_ptr = nullptr;
for (const auto& region : m_mapped_regions)
{
if (!region->contains(vaddr + i * PAGE_SIZE))
continue;
region_ptr = region.ptr();
break;
}
dwarnln("{} pid {}, tid {} made an invalid {} access to 0x{h}",
name(),
pid(),
Thread::current().tid(),
needs_write ? "write" : "read",
vaddr + i * PAGE_SIZE
);
dwarnln(" 0x{h}->0x{h}", vaddr, vaddr + size);
if (region_ptr == nullptr)
dwarnln(" no mapping covers this page");
else
{
dwarnln(" inside region 0x{h}->0x{h} {}{}{}",
region_ptr->vaddr(),
region_ptr->vaddr() + region_ptr->size(),
(region_ptr->flags() & PageTable::Flags::Present) ? 'r' : '-',
(region_ptr->flags() & PageTable::Flags::ReadWrite) ? 'w' : '-',
(region_ptr->flags() & PageTable::Flags::Execute) ? 'x' : '-'
);
}
page_table().debug_dump();
Debug::dump_stack_trace();
MUST(sys_kill(pid(), SIGSEGV));
return BAN::Error::from_errno(EINTR);
}
}
return {};
@ -3539,14 +3763,24 @@ unauthorized_access:
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(ptr, size, needs_write));
for (auto& region : m_mapped_regions)
// FIXME: make stack MemoryRegion?
// FIXME: allow pinning multiple regions
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(ptr);
const size_t first_index = find_mapped_region(vaddr);
for (size_t i = first_index; i < m_mapped_regions.size(); i++)
{
if (!region->contains_fully(reinterpret_cast<vaddr_t>(ptr), size))
auto& region = m_mapped_regions[i];
if (vaddr >= region->vaddr() + region->size())
break;
if (!region->contains_fully(vaddr, size))
continue;
region->pin();
return region.ptr();
}
// FIXME: Make stack MemoryRegion?
return nullptr;
}

View File

@ -12,6 +12,7 @@ namespace Kernel
#if ARCH(x86_64)
static constexpr uint32_t MSR_IA32_FS_BASE = 0xC0000100;
static constexpr uint32_t MSR_IA32_GS_BASE = 0xC0000101;
static constexpr uint32_t MSR_IA32_KERNEL_GS_BASE = 0xC0000102;
#endif
ProcessorID Processor::s_bsp_id { PROCESSOR_NONE };
@ -265,15 +266,52 @@ namespace Kernel
set_interrupt_state(state);
}
void Processor::load_tls()
void Processor::load_segments()
{
const auto addr = scheduler().current_thread().get_tls();
{
const auto addr = scheduler().current_thread().get_fsbase();
#if ARCH(x86_64)
uint32_t ptr_hi = addr >> 32;
uint32_t ptr_lo = addr & 0xFFFFFFFF;
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_FS_BASE));
#elif ARCH(i686)
gdt().set_tls(addr);
gdt().set_fsbase(addr);
#endif
}
{
const auto addr = scheduler().current_thread().get_gsbase();
#if ARCH(x86_64)
uint32_t ptr_hi = addr >> 32;
uint32_t ptr_lo = addr & 0xFFFFFFFF;
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
#elif ARCH(i686)
gdt().set_gsbase(addr);
#endif
}
}
void Processor::load_fsbase()
{
const auto addr = scheduler().current_thread().get_fsbase();
#if ARCH(x86_64)
uint32_t ptr_hi = addr >> 32;
uint32_t ptr_lo = addr & 0xFFFFFFFF;
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_FS_BASE));
#elif ARCH(i686)
gdt().set_fsbase(addr);
#endif
}
void Processor::load_gsbase()
{
const auto addr = scheduler().current_thread().get_gsbase();
#if ARCH(x86_64)
uint32_t ptr_hi = addr >> 32;
uint32_t ptr_lo = addr & 0xFFFFFFFF;
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
#elif ARCH(i686)
gdt().set_gsbase(addr);
#endif
}

View File

@ -282,7 +282,8 @@ namespace Kernel
}
Processor::gdt().set_tss_stack(thread->kernel_stack_top());
Processor::load_tls();
if (thread->is_userspace())
Processor::load_segments();
*interrupt_stack = thread->interrupt_stack();
*interrupt_registers = thread->interrupt_registers();

View File

@ -124,8 +124,8 @@ namespace Kernel
case SYS_WAIT:
case SYS_ACCEPT:
case SYS_CONNECT:
case SYS_RECVFROM:
case SYS_SENDTO:
case SYS_RECVMSG:
case SYS_SENDMSG:
case SYS_FLOCK:
return true;
default:

View File

@ -417,6 +417,11 @@ namespace Kernel
m_cursor_shown = (ch == 'h');
return reset_ansi();
}
if (m_ansi_state.question && m_ansi_state.nums[0] == 2004)
{
// bracketed paste mode, there is no pasting so this is a no-op
return reset_ansi();
}
reset_ansi();
dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character {}", static_cast<char>(ch));
return;

View File

@ -328,7 +328,8 @@ namespace Kernel
thread->m_kernel_stack = TRY(m_kernel_stack->clone(new_process->page_table()));
thread->m_userspace_stack = TRY(m_userspace_stack->clone(new_process->page_table()));
thread->m_tls = m_tls;
thread->m_fsbase = m_fsbase;
thread->m_gsbase = m_gsbase;
thread->m_state = State::NotStarted;
@ -385,7 +386,7 @@ namespace Kernel
vaddr_t vaddr = userspace_stack_top() - needed_size;
const size_t page_count = BAN::Math::div_round_up(needed_size, PAGE_SIZE);
const size_t page_count = BAN::Math::div_round_up<size_t>(needed_size, PAGE_SIZE);
for (size_t i = 0; i < page_count; i++)
TRY(m_userspace_stack->allocate_page_for_demand_paging(vaddr + i * PAGE_SIZE));
@ -549,12 +550,14 @@ namespace Kernel
vaddr_t signal_handler;
{
SpinLockGuard _(m_process->m_signal_lock);
ASSERT(!(m_process->m_signal_handlers[i].sa_flags & SA_SIGINFO));
signal_handler = (vaddr_t)m_process->m_signal_handlers[i].sa_handler;
const auto& handler = m_process->m_signal_handlers[i];
signal_handler = (handler.sa_flags & SA_SIGINFO)
? reinterpret_cast<vaddr_t>(handler.sa_sigaction)
: reinterpret_cast<vaddr_t>(handler.sa_handler);
}
if (signal_handler == (vaddr_t)SIG_IGN)
if (signal_handler == reinterpret_cast<vaddr_t>(SIG_IGN))
continue;
if (signal_handler == (vaddr_t)SIG_DFL && is_default_ignored_signal(i))
if (signal_handler == reinterpret_cast<vaddr_t>(SIG_DFL) && is_default_ignored_signal(i))
continue;
return true;
}
@ -585,7 +588,7 @@ namespace Kernel
return false;
}
bool Thread::handle_signal(int signal)
bool Thread::handle_signal(int signal, const siginfo_t& _signal_info)
{
ASSERT(&Thread::current() == this);
ASSERT(is_userspace());
@ -595,16 +598,23 @@ namespace Kernel
auto& interrupt_stack = *reinterpret_cast<InterruptStack*>(kernel_stack_top() - sizeof(InterruptStack));
ASSERT(GDT::is_user_segment(interrupt_stack.cs));
auto signal_info = _signal_info;
if (signal == 0)
{
uint64_t full_pending_mask = m_signal_pending_mask | process().signal_pending_mask();
const uint64_t process_signal_pending_mask = process().signal_pending_mask();
const uint64_t full_pending_mask = m_signal_pending_mask | process_signal_pending_mask;
for (signal = _SIGMIN; signal <= _SIGMAX; signal++)
{
uint64_t mask = 1ull << signal;
const uint64_t mask = 1ull << signal;
if ((full_pending_mask & mask) && !(m_signal_block_mask & mask))
break;
}
ASSERT(signal <= _SIGMAX);
if (process_signal_pending_mask & (1ull << signal))
signal_info = process().m_signal_infos[signal];
else
signal_info = m_signal_infos[signal];
}
else
{
@ -615,19 +625,20 @@ namespace Kernel
vaddr_t signal_handler;
bool has_sa_restart;
vaddr_t signal_stack_top = 0;
{
SpinLockGuard _(m_process->m_signal_lock);
auto& handler = m_process->m_signal_handlers[signal];
ASSERT(!(handler.sa_flags & SA_SIGINFO));
signal_handler = reinterpret_cast<vaddr_t>(handler.sa_handler);
if (handler.sa_flags & SA_RESETHAND)
handler.sa_handler = SIG_DFL;
signal_handler = (handler.sa_flags & SA_SIGINFO)
? reinterpret_cast<vaddr_t>(handler.sa_sigaction)
: reinterpret_cast<vaddr_t>(handler.sa_handler);
has_sa_restart = !!(handler.sa_flags & SA_RESTART);
if (handler.sa_flags & SA_RESETHAND)
handler = { .sa_handler = SIG_DFL, .sa_mask = 0, .sa_flags = 0 };
const auto& alt_stack = m_signal_alt_stack;
if (alt_stack.ss_flags != SS_DISABLE && (handler.sa_flags & SA_ONSTACK) && !currently_on_alternate_stack())
signal_stack_top = reinterpret_cast<vaddr_t>(alt_stack.ss_sp) + alt_stack.ss_size;
@ -661,15 +672,15 @@ namespace Kernel
if (signal_stack_top == 0)
{
pages[0] = (interrupt_stack.sp - 1 * sizeof(uintptr_t)) & PAGE_ADDR_MASK;
pages[1] = (interrupt_stack.sp - 5 * sizeof(uintptr_t)) & PAGE_ADDR_MASK;
pages[0] = (interrupt_stack.sp - 1 * sizeof(uintptr_t) ) & PAGE_ADDR_MASK;
pages[1] = (interrupt_stack.sp - 5 * sizeof(uintptr_t) - sizeof(siginfo_t)) & PAGE_ADDR_MASK;
page_count = 2;
}
else
{
pages[0] = (interrupt_stack.sp - sizeof(uintptr_t)) & PAGE_ADDR_MASK;
pages[1] = (signal_stack_top - 4 * sizeof(uintptr_t)) & PAGE_ADDR_MASK;
pages[2] = (signal_stack_top - 1 * sizeof(uintptr_t)) & PAGE_ADDR_MASK;
pages[0] = (interrupt_stack.sp - 1 * sizeof(uintptr_t) ) & PAGE_ADDR_MASK;
pages[2] = (signal_stack_top - 1 * sizeof(uintptr_t) ) & PAGE_ADDR_MASK;
pages[1] = (signal_stack_top - 4 * sizeof(uintptr_t) - sizeof(siginfo_t)) & PAGE_ADDR_MASK;
page_count = 3;
}
@ -690,6 +701,16 @@ namespace Kernel
interrupt_stack.sp = signal_stack_top;
write_to_stack(interrupt_stack.sp, old_stack);
write_to_stack(interrupt_stack.sp, interrupt_stack.flags);
{
signal_info.si_signo = signal;
signal_info.si_addr = reinterpret_cast<void*>(interrupt_stack.ip);
interrupt_stack.sp -= sizeof(siginfo_t);
*reinterpret_cast<siginfo_t*>(interrupt_stack.sp) = signal_info;
static_assert(sizeof(siginfo_t) % sizeof(uintptr_t) == 0);
}
write_to_stack(interrupt_stack.sp, signal);
write_to_stack(interrupt_stack.sp, signal_handler);
interrupt_stack.ip = (uintptr_t)signal_trampoline;
@ -727,25 +748,29 @@ namespace Kernel
return has_sa_restart;
}
void Thread::add_signal(int signal)
void Thread::add_signal(int signal, const siginfo_t& info)
{
SpinLockGuard _(m_signal_lock);
if (m_process)
{
vaddr_t signal_handler;
{
SpinLockGuard _(m_process->m_signal_lock);
ASSERT(!(m_process->m_signal_handlers[signal].sa_flags & SA_SIGINFO));
signal_handler = (vaddr_t)m_process->m_signal_handlers[signal].sa_handler;
const auto& handler = m_process->m_signal_handlers[signal];
signal_handler = (handler.sa_flags & SA_SIGINFO)
? reinterpret_cast<vaddr_t>(handler.sa_sigaction)
: reinterpret_cast<vaddr_t>(handler.sa_handler);
}
if (signal_handler == (vaddr_t)SIG_IGN)
if (signal_handler == reinterpret_cast<vaddr_t>(SIG_IGN))
return;
if (signal_handler == (vaddr_t)SIG_DFL && is_default_ignored_signal(signal))
if (signal_handler == reinterpret_cast<vaddr_t>(SIG_DFL) && is_default_ignored_signal(signal))
return;
}
const uint64_t mask = 1ull << signal;
m_signal_pending_mask |= mask;
m_signal_infos[signal] = info;
if (this != &Thread::current())
Processor::scheduler().unblock_thread(this);

View File

@ -113,6 +113,18 @@ namespace Kernel
auto& operational = operational_regs();
if (auto page_size_bits = operational.pagesize & 0xFFFF; page_size_bits != 1)
{
dwarnln("XHCI does not support 4096 byte pages");
dwarnln(" supported page sizes:");
for (size_t i = 0; i < 16; i++)
if (page_size_bits & (1 << i))
dwarnln(" {} bytes", 1 << (12 + i));
if (__builtin_popcount(page_size_bits) != 1)
dwarnln(" ... XHCI spec only allows a single supported page size???");
return BAN::Error::from_errno(ENOTSUP);
}
// allocate and program dcbaa
m_dcbaa_region = TRY(DMARegion::create(capabilities.hcsparams1.max_slots * 8));
memset(reinterpret_cast<void*>(m_dcbaa_region->vaddr()), 0, m_dcbaa_region->size());
@ -289,6 +301,9 @@ namespace Kernel
const paddr_t paddr = Heap::get().take_free_page();
if (paddr == 0)
return BAN::Error::from_errno(ENOMEM);
PageTable::with_fast_page(paddr, [] {
memset(PageTable::fast_page_as_ptr(), 0, PAGE_SIZE);
});
m_scratchpad_buffers[i] = paddr;
scratchpad_buffer_array[i] = paddr;
}

View File

@ -11,7 +11,6 @@
#include <kernel/IDT.h>
#include <kernel/Input/PS2/Controller.h>
#include <kernel/InterruptController.h>
#include <kernel/kprint.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>

View File

@ -179,6 +179,7 @@ const char* strerrordesc_np(int error)
case EWOULDBLOCK: return "Operation would block.";
case EXDEV: return "Cross-device link.";
case ENOTBLK: return "Block device required";
case ESHUTDOWN: return "Cannot send after transport endpoint shutdown.";
case EUNKNOWN: return "Unknown error";
}
return nullptr;

1
ports/.gitignore vendored
View File

@ -1,3 +1,4 @@
*/*
!*/patches/
!*/build.sh
.installed_ports

View File

@ -1,6 +1,6 @@
diff -ruN SDL2-2.32.8/cmake/sdlplatform.cmake SDL2-2.32.8-banan_os/cmake/sdlplatform.cmake
--- SDL2-2.32.8/cmake/sdlplatform.cmake 2024-08-14 13:35:43.000000000 +0300
+++ SDL2-2.32.8-banan_os/cmake/sdlplatform.cmake 2025-08-06 02:07:18.347821313 +0300
+++ SDL2-2.32.8-banan_os/cmake/sdlplatform.cmake 2025-11-22 00:45:00.922311100 +0200
@@ -28,6 +28,8 @@
set(SDL_CMAKE_PLATFORM AIX)
elseif(CMAKE_SYSTEM_NAME MATCHES "Minix.*")
@ -12,7 +12,7 @@ diff -ruN SDL2-2.32.8/cmake/sdlplatform.cmake SDL2-2.32.8-banan_os/cmake/sdlplat
endif()
diff -ruN SDL2-2.32.8/CMakeLists.txt SDL2-2.32.8-banan_os/CMakeLists.txt
--- SDL2-2.32.8/CMakeLists.txt 2025-06-03 02:00:39.000000000 +0300
+++ SDL2-2.32.8-banan_os/CMakeLists.txt 2025-08-06 02:19:44.864415796 +0300
+++ SDL2-2.32.8-banan_os/CMakeLists.txt 2025-11-22 00:45:00.923441418 +0200
@@ -14,7 +14,7 @@
set(SDL2_SUBPROJECT ON)
endif()
@ -55,7 +55,7 @@ diff -ruN SDL2-2.32.8/CMakeLists.txt SDL2-2.32.8-banan_os/CMakeLists.txt
+ file(GLOB VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/banan_os/*.cpp)
+ list(APPEND SOURCE_FILES ${VIDEO_SOURCES})
+ set(HAVE_SDL_VIDEO TRUE)
+ list(APPEND EXTRA_LIBS gui input)
+ list(APPEND EXTRA_LIBS gui input clipboard)
+
+ if(SDL_OPENGL)
+ set(SDL_VIDEO_OPENGL 1)
@ -91,7 +91,7 @@ diff -ruN SDL2-2.32.8/CMakeLists.txt SDL2-2.32.8-banan_os/CMakeLists.txt
file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/riscos/*.c)
diff -ruN SDL2-2.32.8/include/SDL_config.h.cmake SDL2-2.32.8-banan_os/include/SDL_config.h.cmake
--- SDL2-2.32.8/include/SDL_config.h.cmake 2025-01-01 17:47:53.000000000 +0200
+++ SDL2-2.32.8-banan_os/include/SDL_config.h.cmake 2025-08-06 02:01:21.085539504 +0300
+++ SDL2-2.32.8-banan_os/include/SDL_config.h.cmake 2025-11-22 00:45:00.924001549 +0200
@@ -307,6 +307,7 @@
#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND @SDL_AUDIO_DRIVER_FUSIONSOUND@
#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC @SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC@
@ -110,7 +110,7 @@ diff -ruN SDL2-2.32.8/include/SDL_config.h.cmake SDL2-2.32.8-banan_os/include/SD
#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB @SDL_VIDEO_DRIVER_DIRECTFB@
diff -ruN SDL2-2.32.8/include/SDL_platform.h SDL2-2.32.8-banan_os/include/SDL_platform.h
--- SDL2-2.32.8/include/SDL_platform.h 2025-01-01 17:47:53.000000000 +0200
+++ SDL2-2.32.8-banan_os/include/SDL_platform.h 2025-08-06 02:01:21.085701327 +0300
+++ SDL2-2.32.8-banan_os/include/SDL_platform.h 2025-11-22 00:45:00.924303894 +0200
@@ -36,6 +36,10 @@
#undef __HAIKU__
#define __HAIKU__ 1
@ -124,7 +124,7 @@ diff -ruN SDL2-2.32.8/include/SDL_platform.h SDL2-2.32.8-banan_os/include/SDL_pl
#define __BSDI__ 1
diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.cpp
--- SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp 1970-01-01 02:00:00.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.cpp 2025-08-06 02:01:21.085876490 +0300
+++ SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.cpp 2025-11-22 00:45:00.924702550 +0200
@@ -0,0 +1,150 @@
+/*
+ Simple DirectMedia Layer
@ -278,7 +278,7 @@ diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp SDL2-2.32.8-bana
+#endif
diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.h SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.h
--- SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.h 1970-01-01 02:00:00.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.h 2025-08-06 02:01:21.085937043 +0300
+++ SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.h 2025-11-22 00:45:00.924820303 +0200
@@ -0,0 +1,34 @@
+/*
+ Simple DirectMedia Layer
@ -316,7 +316,7 @@ diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.h SDL2-2.32.8-banan_
+};
diff -ruN SDL2-2.32.8/src/audio/SDL_audio.c SDL2-2.32.8-banan_os/src/audio/SDL_audio.c
--- SDL2-2.32.8/src/audio/SDL_audio.c 2025-01-01 17:47:53.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/audio/SDL_audio.c 2025-08-06 02:01:21.086082872 +0300
+++ SDL2-2.32.8-banan_os/src/audio/SDL_audio.c 2025-11-22 00:45:00.925178591 +0200
@@ -87,6 +87,9 @@
#ifdef SDL_AUDIO_DRIVER_HAIKU
&HAIKUAUDIO_bootstrap,
@ -329,7 +329,7 @@ diff -ruN SDL2-2.32.8/src/audio/SDL_audio.c SDL2-2.32.8-banan_os/src/audio/SDL_a
#endif
diff -ruN SDL2-2.32.8/src/audio/SDL_sysaudio.h SDL2-2.32.8-banan_os/src/audio/SDL_sysaudio.h
--- SDL2-2.32.8/src/audio/SDL_sysaudio.h 2025-01-01 17:47:53.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/audio/SDL_sysaudio.h 2025-08-06 02:01:21.086309718 +0300
+++ SDL2-2.32.8-banan_os/src/audio/SDL_sysaudio.h 2025-11-22 00:45:00.925759535 +0200
@@ -196,6 +196,7 @@
extern AudioBootStrap WINMM_bootstrap;
extern AudioBootStrap PAUDIO_bootstrap;
@ -340,7 +340,7 @@ diff -ruN SDL2-2.32.8/src/audio/SDL_sysaudio.h SDL2-2.32.8-banan_os/src/audio/SD
extern AudioBootStrap DUMMYAUDIO_bootstrap;
diff -ruN SDL2-2.32.8/src/misc/banan_os/SDL_sysurl.cpp SDL2-2.32.8-banan_os/src/misc/banan_os/SDL_sysurl.cpp
--- SDL2-2.32.8/src/misc/banan_os/SDL_sysurl.cpp 1970-01-01 02:00:00.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/misc/banan_os/SDL_sysurl.cpp 2025-08-06 02:01:21.086457363 +0300
+++ SDL2-2.32.8-banan_os/src/misc/banan_os/SDL_sysurl.cpp 2025-11-22 00:45:00.926117334 +0200
@@ -0,0 +1,30 @@
+/*
+ Simple DirectMedia Layer
@ -372,9 +372,111 @@ diff -ruN SDL2-2.32.8/src/misc/banan_os/SDL_sysurl.cpp SDL2-2.32.8-banan_os/src/
+
+/* vi: set ts=4 sw=4 expandtab: */
+
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.cpp SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.cpp
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.cpp 1970-01-01 02:00:00.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.cpp 2025-11-22 01:10:01.840984523 +0200
@@ -0,0 +1,51 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifdef SDL_VIDEO_DRIVER_BANANOS
+
+#include "SDL_banan_os_clipboard.h"
+
+#include <LibClipboard/Clipboard.h>
+
+int BANANOS_SetClipboardText(_THIS, const char *text) {
+ if (LibClipboard::Clipboard::set_clipboard_text(text).is_error())
+ return -1;
+ return 0;
+}
+
+char *BANANOS_GetClipboardText(_THIS) {
+ auto text_or_error = LibClipboard::Clipboard::get_clipboard_text();
+ if (text_or_error.is_error())
+ return NULL;
+ return SDL_strdup(text_or_error.value().data());
+}
+
+SDL_bool BANANOS_HasClipboardText(_THIS) {
+ auto text_or_error = LibClipboard::Clipboard::get_clipboard_text();
+ if (text_or_error.is_error())
+ return SDL_FALSE;
+ return text_or_error.value().empty() ? SDL_FALSE : SDL_TRUE;
+}
+
+#endif /* SDL_VIDEO_DRIVER_BANANOS */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.h SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.h
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.h 1970-01-01 02:00:00.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.h 2025-11-22 01:10:16.932880273 +0200
@@ -0,0 +1,43 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_BANANOS_CLIPBOARD_H
+#define SDL_BANANOS_CLIPBOARD_H
+
+#include "../../SDL_internal.h"
+
+#include "../SDL_sysvideo.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int BANANOS_SetClipboardText(_THIS, const char *text);
+extern char *BANANOS_GetClipboardText(_THIS);
+extern SDL_bool BANANOS_HasClipboardText(_THIS);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* vi: set ts=4 sw=4 expandtab: */
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.cpp SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.cpp
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.cpp 1970-01-01 02:00:00.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.cpp 2025-08-06 02:01:21.086557935 +0300
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.cpp 2025-11-22 00:45:00.926337964 +0200
@@ -0,0 +1,60 @@
+/*
+ Simple DirectMedia Layer
@ -438,7 +540,7 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.cpp SDL2-2.32.
+/* vi: set ts=4 sw=4 expandtab: */
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.h SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.h
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.h 1970-01-01 02:00:00.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.h 2025-08-06 02:01:21.086603053 +0300
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.h 2025-11-22 00:45:00.926434625 +0200
@@ -0,0 +1,45 @@
+/*
+ Simple DirectMedia Layer
@ -487,8 +589,8 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.h SDL2-2.32.8-
+/* vi: set ts=4 sw=4 expandtab: */
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_video.cpp
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp 1970-01-01 02:00:00.000000000 +0200
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_video.cpp 2025-08-21 02:32:59.649175565 +0300
@@ -0,0 +1,724 @@
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_video.cpp 2025-11-22 01:08:26.204647073 +0200
@@ -0,0 +1,729 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
@ -518,6 +620,7 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp SDL2-2.32.8-bana
+#include "../../events/SDL_events_c.h"
+}
+
+#include "SDL_banan_os_clipboard.h"
+#include "SDL_banan_os_message_box.h"
+
+#include <BAN/Debug.h>
@ -1199,6 +1302,10 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp SDL2-2.32.8-bana
+ device->GL_MakeCurrent = BANANOS_GL_MakeCurrent;
+ device->GL_SwapWindow = BANANOS_GL_SwapWindow;
+
+ device->SetClipboardText = BANANOS_SetClipboardText;
+ device->GetClipboardText = BANANOS_GetClipboardText;
+ device->HasClipboardText = BANANOS_HasClipboardText;
+
+ device->free = BANANOS_free;
+
+ return device;
@ -1215,7 +1322,7 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp SDL2-2.32.8-bana
+/* vi: set ts=4 sw=4 expandtab: */
diff -ruN SDL2-2.32.8/src/video/SDL_sysvideo.h SDL2-2.32.8-banan_os/src/video/SDL_sysvideo.h
--- SDL2-2.32.8/src/video/SDL_sysvideo.h 2025-05-20 00:24:41.000000000 +0300
+++ SDL2-2.32.8-banan_os/src/video/SDL_sysvideo.h 2025-08-06 02:01:21.086873550 +0300
+++ SDL2-2.32.8-banan_os/src/video/SDL_sysvideo.h 2025-11-22 00:45:00.927152737 +0200
@@ -462,6 +462,7 @@
extern VideoBootStrap WINDOWS_bootstrap;
extern VideoBootStrap WINRT_bootstrap;
@ -1226,7 +1333,7 @@ diff -ruN SDL2-2.32.8/src/video/SDL_sysvideo.h SDL2-2.32.8-banan_os/src/video/SD
extern VideoBootStrap Android_bootstrap;
diff -ruN SDL2-2.32.8/src/video/SDL_video.c SDL2-2.32.8-banan_os/src/video/SDL_video.c
--- SDL2-2.32.8/src/video/SDL_video.c 2025-05-20 00:24:41.000000000 +0300
+++ SDL2-2.32.8-banan_os/src/video/SDL_video.c 2025-08-06 02:01:21.087224294 +0300
+++ SDL2-2.32.8-banan_os/src/video/SDL_video.c 2025-11-22 00:45:00.928264617 +0200
@@ -96,6 +96,9 @@
#ifdef SDL_VIDEO_DRIVER_HAIKU
&HAIKU_bootstrap,

23
ports/SDL2_image/build.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash ../install.sh
NAME='SDL2_image'
VERSION='2.8.8'
DOWNLOAD_URL="https://github.com/libsdl-org/SDL_image/releases/download/release-$VERSION/SDL2_image-$VERSION.tar.gz#2213b56fdaff2220d0e38c8e420cbe1a83c87374190cba8c70af2156097ce30a"
DEPENDENCIES=('SDL2' 'libpng' 'libjpeg' 'libtiff' 'libwebp')
configure() {
$BANAN_CMAKE --fresh -S . -B build -G Ninja \
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
-DCMAKE_INSTALL_PREFIX='/usr' \
-DCMAKE_BUILD_TYPE=Release \
-DSDL2IMAGE_AVIF=OFF \
|| exit 1
}
build() {
$BANAN_CMAKE --build build || exit 1
}
install() {
$BANAN_CMAKE --install build || exit 1
}

8
ports/SDL_mixer/build.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash ../install.sh
NAME='SDL_mixer'
VERSION='1.2.12'
DOWNLOAD_URL="https://github.com/libsdl-org/SDL_mixer/archive/refs/tags/release-$VERSION.tar.gz#4176dfc887664419bfd16c41013c6cf0c48eca6b95ae3c34205630e8a7a94faa"
TAR_CONTENT="SDL_mixer-release-$VERSION"
CONFIG_SUB=('build-scripts/config.sub')
DEPENDENCIES=('libmikmod' 'libiconv' 'sdl12-compat')

View File

@ -0,0 +1,31 @@
diff -ruN SDL_mixer-1.2.12/configure SDL_mixer-1.2.12-banan_os/configure
--- SDL_mixer-1.2.12/configure 2012-01-16 00:00:28.000000000 +0200
+++ SDL_mixer-1.2.12-banan_os/configure 2025-11-16 03:27:17.615555034 +0200
@@ -4073,6 +4073,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
;;
@@ -9083,6 +9087,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"

32
ports/SuperTux/build.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/bash ../install.sh
NAME='SuperTux'
VERSION='0.6.3'
DOWNLOAD_URL="https://github.com/SuperTux/supertux/releases/download/v$VERSION/SuperTux-v$VERSION-Source.tar.gz#f7940e6009c40226eb34ebab8ffb0e3a894892d891a07b35d0e5762dd41c79f6"
TAR_CONTENT="SuperTux-v$VERSION-Source"
DEPENDENCIES=('boost' 'SDL2' 'SDL2_image' 'curl' 'openal-soft' 'libvorbis' 'freetype' 'physfs' 'glm')
configure() {
mkdir -p build
pushd build
$BANAN_CMAKE \
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
-G Ninja --fresh .. \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DINSTALL_SUBDIR_BIN=bin \
-DBUILD_DOCUMENTATION=OFF \
-DENABLE_OPENGL=OFF \
-DENABLE_BOOST_STATIC_LIBS=ON \
|| exit 1
popd
# crashes in `std::ostream::sentry::sentry(std::ostream&)` with shared boost
}
build() {
$BANAN_CMAKE --build build || exit 1
}
install() {
$BANAN_CMAKE --install build || exit 1
}

View File

@ -0,0 +1,52 @@
diff -ruN SuperTux-0.6.3/CMakeLists.txt SuperTux-0.6.3-banan_os/CMakeLists.txt
--- SuperTux-0.6.3/CMakeLists.txt 2021-12-23 01:01:57.000000000 +0200
+++ SuperTux-0.6.3-banan_os/CMakeLists.txt 2025-11-02 20:57:03.725932455 +0200
@@ -171,7 +171,7 @@
else(ENABLE_BOOST_STATIC_LIBS)
set(Boost_USE_STATIC_LIBS FALSE)
endif(ENABLE_BOOST_STATIC_LIBS)
-find_package(Boost REQUIRED COMPONENTS filesystem system date_time locale)
+find_package(Boost REQUIRED COMPONENTS filesystem date_time locale)
include_directories(SYSTEM ${Boost_INCLUDE_DIR})
link_directories(${Boost_LIBRARY_DIRS})
@@ -507,6 +507,7 @@
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_INSTALL_PREFIX=${SQUIRREL_PREFIX}
+ -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DINSTALL_INC_DIR=include
-DCMAKE_POSITION_INDEPENDENT_CODE=ON)
@@ -966,7 +967,7 @@
endif()
endif()
target_include_directories(supertux2_lib SYSTEM PUBLIC ${SDL_TTF_PREFIX}/include/SDL2)
-target_link_libraries(supertux2_lib PUBLIC SDL_ttf_lib)
+target_link_libraries(supertux2_lib PUBLIC libSDL2_ttf.a)
if(VCPKG_BUILD)
target_link_libraries(supertux2_lib PUBLIC freetype)
else()
@@ -977,9 +978,10 @@
target_link_libraries(supertux2_lib PUBLIC ${HARFBUZZ_LIBRARY} ${FRIBIDI_LIBRARY} ${RAQM_LIBRARY})
endif()
-target_link_libraries(supertux2_lib PUBLIC squirrel_lib)
-target_link_libraries(supertux2_lib PUBLIC sqstdlib_lib)
-target_link_libraries(supertux2_lib PUBLIC tinygettext_lib)
+target_link_libraries(supertux2_lib PUBLIC libsquirrel_static.a)
+target_link_libraries(supertux2_lib PUBLIC libsqstdlib_static.a)
+target_link_libraries(supertux2_lib PUBLIC libtinygettext.a)
+
target_link_libraries(supertux2_lib PUBLIC sexp)
target_link_libraries(supertux2_lib PUBLIC savepng)
target_link_libraries(supertux2_lib PUBLIC partio_zip_lib)
@@ -1025,7 +1027,7 @@
if(VCPKG_BUILD)
target_link_libraries(supertux2_lib PUBLIC ${CURL_LIBRARIES})
else()
- target_link_libraries(supertux2_lib PUBLIC ${CURL_LIBRARY})
+ target_link_libraries(supertux2_lib PUBLIC ${CURL_LIBRARY} ssl crypto zstd z)
endif()
endif(HAVE_LIBCURL)
endif(NOT EMSCRIPTEN)

View File

@ -0,0 +1,11 @@
diff -ruN SuperTux-0.6.3/external/partio_zip/zip_manager.hpp SuperTux-0.6.3-banan_os/external/partio_zip/zip_manager.hpp
--- SuperTux-0.6.3/external/partio_zip/zip_manager.hpp 2021-12-23 01:01:58.000000000 +0200
+++ SuperTux-0.6.3-banan_os/external/partio_zip/zip_manager.hpp 2025-11-02 20:16:29.691656288 +0200
@@ -44,6 +44,7 @@
#include <fstream>
#include <iostream>
#include <map>
+#include <memory>
#include <string>
#include <stdexcept>
#include <vector>

View File

@ -1,8 +1,8 @@
#!/bin/bash ../install.sh
NAME='binutils'
VERSION='2.44'
DOWNLOAD_URL="https://ftpmirror.gnu.org/gnu/binutils/binutils-$VERSION.tar.gz#0cdd76777a0dfd3dd3a63f215f030208ddb91c2361d2bcc02acec0f1c16b6a2e"
VERSION='2.45'
DOWNLOAD_URL="https://ftpmirror.gnu.org/gnu/binutils/binutils-$VERSION.tar.gz#8a3eb4b10e7053312790f21ee1a38f7e2bbd6f4096abb590d3429e5119592d96"
DEPENDENCIES=('zlib' 'zstd')
MAKE_INSTALL_TARGETS=('install-strip')
CONFIGURE_OPTIONS=(
@ -22,12 +22,3 @@ pre_configure() {
unset PKG_CONFIG_LIBDIR
unset PKG_CONFIG_PATH
}
post_install() {
# remove libtool files
rm -f $BANAN_SYSROOT/usr/lib/libbfd.la
rm -f $BANAN_SYSROOT/usr/lib/libctf.la
rm -f $BANAN_SYSROOT/usr/lib/libctf-nobfd.la
rm -f $BANAN_SYSROOT/usr/lib/libopcodes.la
rm -f $BANAN_SYSROOT/usr/lib/libsframe.la
}

View File

@ -1 +0,0 @@
../../../toolchain/binutils-2.44.patch

View File

@ -0,0 +1 @@
../../../toolchain/binutils-2.45.patch

25
ports/boost/build.sh Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash ../install.sh
NAME='boost'
VERSION='1.89.0'
DOWNLOAD_URL="https://archives.boost.io/release/$VERSION/source/boost_${VERSION//./_}.tar.gz#9de758db755e8330a01d995b0a24d09798048400ac25c03fc5ea9be364b13c93"
TAR_CONTENT="boost_${VERSION//./_}"
DEPENDENCIES=('zlib' 'zstd' 'libiconv')
configure() {
# stacktrace fails on multiple definition of __cxa_allocate_exception because our libstdc++ is static
./bootstrap.sh \
--prefix="$BANAN_SYSROOT/usr" \
--without-icu \
--without-libraries='python,stacktrace' \
|| exit 1
echo "using gcc : : $CXX ;" > user-config.jam
}
build() {
./b2 --user-config=user-config.jam toolset=gcc target-os=banan_os || exit 1
}
install() {
./b2 --user-config=user-config.jam toolset=gcc target-os=banan_os install || exit 1
}

View File

@ -0,0 +1,115 @@
diff -ruN boost_1_89_0/boost/config/detail/select_platform_config.hpp boost_1_89_0-banan_os/boost/config/detail/select_platform_config.hpp
--- boost_1_89_0/boost/config/detail/select_platform_config.hpp 2025-08-06 21:49:08.000000000 +0300
+++ boost_1_89_0-banan_os/boost/config/detail/select_platform_config.hpp 2025-10-29 21:16:39.964658105 +0200
@@ -93,6 +93,10 @@
// Web assembly:
# define BOOST_PLATFORM_CONFIG "boost/config/platform/wasm.hpp"
+#elif defined (__banan_os__)
+// banan-os:
+# define BOOST_PLATFORM_CONFIG "boost/config/platform/banan-os.hpp"
+
#else
# if defined(unix) \
@@ -139,6 +143,7 @@
# include "boost/config/platform/symbian.hpp"
# include "boost/config/platform/cray.hpp"
# include "boost/config/platform/vms.hpp"
+# include "boost/config/platform/banan-os.hpp"
# include <boost/config/detail/posix_features.hpp>
diff -ruN boost_1_89_0/boost/config/platform/banan-os.hpp boost_1_89_0-banan_os/boost/config/platform/banan-os.hpp
--- boost_1_89_0/boost/config/platform/banan-os.hpp 1970-01-01 02:00:00.000000000 +0200
+++ boost_1_89_0-banan_os/boost/config/platform/banan-os.hpp 2025-10-29 21:21:58.791813238 +0200
@@ -0,0 +1,29 @@
+// (C) Copyright Oskari Alaranta 2025.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org for most recent version.
+
+// banan-os specific config options:
+
+#define BOOST_PLATFORM "banan-os"
+
+#define BOOST_HAS_UNISTD_H
+#define BOOST_HAS_STDINT_H
+
+#ifndef BOOST_DISABLE_THREADS
+# define BOOST_HAS_THREADS
+#endif
+
+//
+// thread API's not auto detected:
+//
+#define BOOST_HAS_SCHED_YIELD
+#define BOOST_HAS_GETTIMEOFDAY
+
+// boilerplate code:
+#include <boost/config/detail/posix_features.hpp>
+
+
+
diff -ruN boost_1_89_0/tools/build/src/tools/features/os-feature.jam boost_1_89_0-banan_os/tools/build/src/tools/features/os-feature.jam
--- boost_1_89_0/tools/build/src/tools/features/os-feature.jam 2025-08-06 21:49:15.000000000 +0300
+++ boost_1_89_0-banan_os/tools/build/src/tools/features/os-feature.jam 2025-10-29 21:14:14.978467634 +0200
@@ -11,7 +11,7 @@
none
aix android appletv bsd cygwin darwin freebsd haiku hpux iphone linux
netbsd openbsd osf qnx qnxnto sgi solaris unix unixware windows vms vxworks
- freertos
+ freertos banan_os
# Not actually an OS -- used for targeting bare metal where object
# format is ELF. This catches both -elf and -eabi gcc targets as well
@@ -80,7 +80,7 @@
*Allowed values:* `aix`, `android`, `appletv`, `bsd`, `cygwin`, `darwin`,
`freebsd`, `haiku`, `hpux`, `iphone`, `linux`, `netbsd`, `openbsd`, `osf`,
`qnx`, `qnxnto`, `sgi`, `solaris`, `unix`, `unixware`, `windows`, `vms`,
-`vxworks`, `freertos`.
+`vxworks`, `freertos`, `banan_os`.
+
Specifies the operating system for which the code is to be generated. The
compiler you used should be the compiler for that operating system. This option
diff -ruN boost_1_89_0/tools/build/src/tools/gcc.jam boost_1_89_0-banan_os/tools/build/src/tools/gcc.jam
--- boost_1_89_0/tools/build/src/tools/gcc.jam 2025-08-06 21:49:15.000000000 +0300
+++ boost_1_89_0-banan_os/tools/build/src/tools/gcc.jam 2025-10-29 21:12:59.730889504 +0200
@@ -204,6 +204,7 @@
case *linux* : target-os ?= linux ;
case *aix* : target-os ?= aix ;
case *hpux* : target-os ?= hpux ;
+ case *banan_os* : target-os ?= banan_os ;
# TODO: finish this list.
}
}
@@ -406,6 +407,7 @@
threading-flags <target-os>cygwin/<threadapi>pthread : -pthread ;
threading-flags <target-os>solaris : -pthreads : rt ;
threading-flags <target-os>qnx : -pthread ;
+ threading-flags <target-os>banan_os : -pthread ;
local bsd = [ MATCH ^(.*bsd)$ : $(all-os) ] ;
threading-flags <target-os>$(bsd) : -pthread ;
@@ -413,7 +415,7 @@
# iOS doesn't need pthread flag according to the https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/pthread.3.html
# The default system libraries include pthread functions. No additional libraries or CFLAGS are necessary to use this API.
local no-threading = android beos haiku sgi darwin vxworks iphone appletv ;
- local threading-generic-os = [ set.difference $(all-os) : $(no-threading) $(bsd) windows cygwin solaris qnx ] ;
+ local threading-generic-os = [ set.difference $(all-os) : $(no-threading) $(bsd) windows cygwin solaris qnx banan_os ] ;
threading-flags <target-os>$(threading-generic-os) : -pthread : rt ;
}
diff -ruN boost_1_89_0/tools/build/src/tools/python.jam boost_1_89_0-banan_os/tools/build/src/tools/python.jam
--- boost_1_89_0/tools/build/src/tools/python.jam 2025-08-06 21:49:15.000000000 +0300
+++ boost_1_89_0-banan_os/tools/build/src/tools/python.jam 2025-10-29 21:09:10.276185725 +0200
@@ -667,6 +667,7 @@
case darwin : return ;
case windows : return ;
case haiku : return ;
+ case banan_os : return ;
case hpux : return <library>rt ;
case *bsd : return <library>pthread <toolset>gcc:<library>util ;

View File

@ -18,8 +18,3 @@ CONFIGURE_OPTIONS=(
'--with-ca-bundle=/etc/ssl/certs/ca-certificates.crt'
'--without-ca-path'
)
post_install() {
# remove libtool file
rm -f $BANAN_SYSROOT/usr/lib/libcurl.la
}

View File

@ -4,8 +4,3 @@ NAME='expat'
VERSION='2.7.1'
DOWNLOAD_URL="https://github.com/libexpat/libexpat/releases/download/R_2_7_1/expat-$VERSION.tar.gz#0cce2e6e69b327fc607b8ff264f4b66bdf71ead55a87ffd5f3143f535f15cfa2"
CONFIG_SUB=('conftools/config.sub')
post_install() {
# remove libtool file
rm -f $BANAN_SYSROOT/usr/lib/libexpat.la
}

View File

@ -3,13 +3,8 @@
NAME='freetype'
VERSION='2.13.3'
DOWNLOAD_URL="https://download.savannah.gnu.org/releases/freetype/freetype-$VERSION.tar.gz#5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747"
DEPENDENCIES=('zlib' 'libpng')
CONFIG_SUB=('builds/unix/config.sub')
CONFIGURE_OPTIONS=(
'lt_cv_deplibs_check_method=pass_all'
)
post_install() {
# remove libtool file
rm -f $BANAN_SYSROOT/usr/lib/libfreetype.la
}

View File

@ -27,10 +27,3 @@ build() {
make -j$(nproc) all-target-libgcc CFLAGS_FOR_TARGET="$xcflags" || exit 1
make -j$(nproc) all-target-libstdc++-v3 || exit 1
}
post_install() {
# remove libtool files
rm -f $BANAN_SYSROOT/usr/lib/libstdc++.la
rm -f $BANAN_SYSROOT/usr/lib/libstdc++exp.la
rm -f $BANAN_SYSROOT/usr/lib/libsupc++.la
}

23
ports/glm/build.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash ../install.sh
NAME='glm'
VERSION='1.0.2'
DOWNLOAD_URL="https://github.com/g-truc/glm/archive/refs/tags/$VERSION.tar.gz#19edf2e860297efab1c74950e6076bf4dad9de483826bc95e2e0f2c758a43f65"
configure() {
$BANAN_CMAKE \
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
-B build -G Ninja --fresh . \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DGLM_BUILD_TESTS=OFF \
|| exit 1
}
build() {
$BANAN_CMAKE --build build || exit 1
}
install() {
$BANAN_CMAKE --install build || exit 1
}

View File

@ -7,8 +7,3 @@ CONFIG_SUB=('configfsf.sub')
CONFIGURE_OPTIONS=(
'CFLAGS=-std=c17'
)
post_install() {
# remove libtool file
rm -f $BANAN_SYSROOT/usr/lib/libgmp.la
}

View File

@ -11,6 +11,12 @@ fi
source "$BANAN_ROOT_DIR/script/config.sh"
installed_file="$BANAN_PORT_DIR/.installed_ports"
if [ -z $DONT_REMOVE_INSTALLED ]; then
export DONT_REMOVE_INSTALLED=1
rm -f "$installed_file"
fi
export PATH="$BANAN_TOOLCHAIN_PREFIX/bin:$PATH"
export PKG_CONFIG_DIR=''
@ -29,10 +35,6 @@ export OBJDUMP="$BANAN_TOOLCHAIN_TRIPLE-objdump"
export STRIP="$BANAN_TOOLCHAIN_TRIPLE-strip"
export CXXFILT="$BANAN_TOOLCHAIN_TRIPLE-c++filt"
pushd "$BANAN_ROOT_DIR" >/dev/null
./bos all && ./bos install || exit 1
popd >/dev/null
if [ "$BANAN_ARCH" = "i686" ]; then
export LDFLAGS="-shared-libgcc"
fi
@ -78,13 +80,17 @@ post_configure() {
}
configure() {
pre_configure
configure_options=("--host=$BANAN_ARCH-pc-banan_os" '--prefix=/usr')
configure_options+=("${CONFIGURE_OPTIONS[@]}")
./configure "${configure_options[@]}" || exit 1
}
post_configure
pre_build() {
:
}
post_build() {
:
}
build() {
@ -102,13 +108,9 @@ post_install() {
}
install() {
pre_install
for target in "${MAKE_INSTALL_TARGETS[@]}"; do
make $target "DESTDIR=$BANAN_SYSROOT" || exit 1
done
post_install
}
source $1
@ -118,7 +120,30 @@ if [ -z $NAME ] || [ -z $VERSION ] || [ -z $DOWNLOAD_URL ]; then
exit 1
fi
build_dir="$NAME-$VERSION-$BANAN_ARCH"
if [ ! -d "$build_dir" ]; then
rm -f '.compile_hash'
fi
if [ ! -f '.compile_hash' ] && [ -f "$installed_file" ]; then
sed -i "/^$NAME-$VERSION$/d" "$installed_file"
fi
if grep -qsxF "$NAME-$VERSION" "$installed_file"; then
exit 0
fi
pushd "$BANAN_ROOT_DIR" >/dev/null
./bos all && ./bos install || exit 1
popd >/dev/null
for dependency in "${DEPENDENCIES[@]}"; do
if [ ! -d "../$dependency" ]; then
echo "Could not find dependency '$dependency' or port '$NAME'"
exit 1
fi
pushd "../$dependency" >/dev/null
pwd
if ! ./build.sh; then
@ -128,12 +153,6 @@ for dependency in "${DEPENDENCIES[@]}"; do
popd >/dev/null
done
build_dir="$NAME-$VERSION-$BANAN_ARCH"
if [ ! -d "$build_dir" ]; then
rm -f ".compile_hash"
fi
if [ "$VERSION" = "git" ]; then
regex="(.*/.*\.git)#(.*)"
@ -186,7 +205,7 @@ else
exit 1
fi
regex='(.*\.tar\..*)'
regex='(.*\.tar\..*|.*\.tgz)'
if [[ $FILE_NAME =~ $regex ]] && [ ! -d "$build_dir" ]; then
tar xf "$FILE_NAME" || exit 1
@ -219,9 +238,20 @@ cd "$build_dir"
if (( $needs_compile )); then
config_sub_update
pre_configure
configure
post_configure
pre_build
build
post_build
sha256sum "$BANAN_SYSROOT/usr/lib/libc.a" > "../.compile_hash"
fi
pre_install
install
grep -qsxF "$NAME-$VERSION" "$installed_file" || echo "$NAME-$VERSION" >> "$installed_file"
post_install
find "$BANAN_SYSROOT/usr/lib" -name '*.la' -delete

View File

@ -4,8 +4,3 @@ NAME='libffi'
VERSION='3.5.2'
DOWNLOAD_URL="https://github.com/libffi/libffi/releases/download/v$VERSION/libffi-$VERSION.tar.gz#f3a3082a23b37c293a4fcd1053147b371f2ff91fa7ea1b2a52e335676bac82dc"
CONFIG_SUB=('config.sub')
post_install() {
# remove libtool file
rm -f $BANAN_SYSROOT/usr/lib/libffi.la
}

View File

@ -12,9 +12,3 @@ CONFIGURE_OPTIONS=(
pre_configure() {
echo '#include_next <sys/types.h>' > srclib/sys_types.in.h
}
post_install() {
# remove libtool file
rm -f $BANAN_SYSROOT/usr/lib/libcharset.la
rm -f $BANAN_SYSROOT/usr/lib/libiconv.la
}

View File

@ -5,8 +5,3 @@ VERSION='9f'
DOWNLOAD_URL="https://www.ijg.org/files/jpegsrc.v9f.tar.gz#04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b"
TAR_CONTENT="jpeg-$VERSION"
CONFIG_SUB=('config.sub')
post_install() {
# remove libtool files
rm -f $BANAN_SYSROOT/usr/lib/libjpeg.la
}

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

@ -0,0 +1,6 @@
#!/bin/bash ../install.sh
NAME='libmikmod'
VERSION='3.3.13'
DOWNLOAD_URL="https://sourceforge.net/projects/mikmod/files/libmikmod/$VERSION/libmikmod-$VERSION.tar.gz#9fc1799f7ea6a95c7c5882de98be85fc7d20ba0a4a6fcacae11c8c6b382bb207"
CONFIG_SUB=('autotools/config.sub')

View File

@ -0,0 +1,31 @@
diff -ruN libmikmod-3.3.13/configure libmikmod-3.3.13-banan_os/configure
--- libmikmod-3.3.13/configure 2025-04-20 04:55:10.000000000 +0300
+++ libmikmod-3.3.13-banan_os/configure 2025-11-16 03:32:52.087690874 +0200
@@ -5962,6 +5962,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
;;
@@ -11733,6 +11737,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"

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

@ -0,0 +1,6 @@
#!/bin/bash ../install.sh
NAME='libogg'
VERSION='1.3.6'
DOWNLOAD_URL="https://github.com/xiph/ogg/releases/download/v$VERSION/libogg-$VERSION.tar.gz#83e6704730683d004d20e21b8f7f55dcb3383cdf84c0daedf30bde175f774638"
CONFIG_SUB=('config.sub')

View File

@ -0,0 +1,20 @@
diff -ruN libogg-1.3.6/configure libogg-1.3.6-banan_os/configure
--- libogg-1.3.6/configure 2025-06-16 19:02:25.000000000 +0300
+++ libogg-1.3.6-banan_os/configure 2025-10-31 22:25:25.050050235 +0200
@@ -10622,6 +10622,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

@ -5,9 +5,3 @@ VERSION='1.6.48'
DOWNLOAD_URL="https://download.sourceforge.net/libpng/libpng-$VERSION.tar.gz#68f3d83a79d81dfcb0a439d62b411aa257bb4973d7c67cd1ff8bdf8d011538cd"
DEPENDENCIES=('zlib')
CONFIG_SUB=('config.sub')
post_install() {
# remove libtool files
rm -f $BANAN_SYSROOT/usr/lib/libpng.la
rm -f $BANAN_SYSROOT/usr/lib/libpng16.la
}

10
ports/libsndfile/build.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash ../install.sh
NAME='libsndfile'
VERSION='1.2.2'
DOWNLOAD_URL="https://github.com/libsndfile/libsndfile/releases/download/$VERSION/libsndfile-$VERSION.tar.xz#3799ca9924d3125038880367bf1468e53a1b7e3686a934f098b7e1d286cdb80e"
_DEPENDENCIES=('ca-certificates' 'openssl' 'zlib' 'zstd')
CONFIG_SUB=('build-aux/config.sub')
CONFIGURE_OPTIONS=(
'CFLAGS=-std=c11'
)

View File

@ -0,0 +1,48 @@
diff -ruN libsndfile-1.2.2/configure libsndfile-1.2.2-banan_os/configure
--- libsndfile-1.2.2/configure 2023-08-13 12:22:03.000000000 +0300
+++ libsndfile-1.2.2-banan_os/configure 2025-08-09 21:50:50.046135494 +0300
@@ -10059,6 +10059,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
;;
@@ -15720,6 +15724,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"
@@ -19754,6 +19768,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

@ -6,9 +6,3 @@ DOWNLOAD_URL="https://download.osgeo.org/libtiff/tiff-$VERSION.tar.gz#67160e3457
TAR_CONTENT="tiff-$VERSION"
DEPENDENCIES=('zlib' 'zstd' 'libjpeg')
CONFIG_SUB=('config/config.sub')
post_install() {
# remove libtool files
rm -f $BANAN_SYSROOT/usr/lib/libtiff.la
rm -f $BANAN_SYSROOT/usr/lib/libtiffxx.la
}

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