Compare commits

..

35 Commits

Author SHA1 Message Date
Bananymous 0ff365c7f0 ports: Add qemu port 2025-08-21 03:11:16 +03:00
Bananymous 214e7a5672 ports: Add glib port 2025-08-21 03:11:16 +03:00
Bananymous 24b69a6dea ports: Add libffi port 2025-08-21 03:11:16 +03:00
Bananymous 699235147c ports: Add pcre2 port 2025-08-21 03:11:16 +03:00
Bananymous 72ad413a61 ports/SDL2: Handle window focus events 2025-08-21 03:11:16 +03:00
Bananymous f11bb082e4 WindowServer/LibGUI: Add window focus events 2025-08-21 03:11:16 +03:00
Bananymous 2f3fd6867d Kernel: Add VERY HACKY MAP_FIXED fix
This definitely will break stuff but I don't think anything depends on
this (except maybe dynamic loader)

This WILL get fixed soon (I hope :D)
2025-08-21 03:11:16 +03:00
Bananymous 350ae90bb6 Kernel: Make all futexes shared
Some stuff tries to use shared futexes so make them all shared. Private
futexes would be faster as they are process specific but supporting both
would need some reworks
2025-08-21 02:56:17 +03:00
Bananymous fb61cab70d LibC: Rewrite pthread_mutex using a futex 2025-08-21 02:52:49 +03:00
Bananymous 1d6c08478d LibC: Fix sigsetjmp
the call from C sigsetjmp messed up rbp, now sigsetjmp is also written
in assembly.

I did not test the 32 bit code, just ported the tested 64 bit version
over :D
2025-08-21 02:52:49 +03:00
Bananymous 0dfe0b7023 Kernel/LibC: Implement sigaltstack 2025-08-21 02:52:49 +03:00
Bananymous def236b7cd Kernel/LibC: Implement sigwait 2025-08-20 20:16:19 +03:00
Bananymous 247743ef9c Kernel/LibC: Implement sigsuspend 2025-08-20 20:14:54 +03:00
Bananymous 49122cf729 Kernel: Allow adding signals to thread that are blocked 2025-08-20 18:35:18 +03:00
Bananymous 84f579be81 ports: Add nano port 2025-08-19 17:00:14 +03:00
Bananymous 3d5f23a1b2 LibC: Implement wctomb 2025-08-19 16:44:18 +03:00
Bananymous 8b26b6604d LibC: Make mbstate_t into int
This is not used, but makes more sense than an empty struct
2025-08-19 16:29:46 +03:00
Bananymous f88e55ffa8 ports: Add nyancat port 2025-08-19 16:23:30 +03:00
Bananymous 34bdcb12e5 Kernel: Fix termios and enter key handling
Enter key now produces expected \r which gets converted to \n by default
by the ICRNL input flag.

Also input flags are now handled always, not just when ICANON is set.
I don't know why I though ICANON should disable input handling
2025-08-19 16:23:30 +03:00
Bananymous 95b353dae5 LibInput: Fix numpad keycode generation
I had made this function with broken PS/2 scancode set 3, so it seemed
like it worked
2025-08-19 16:23:30 +03:00
Bananymous 6560f229b1 Kernel: Fix PS/2 scancode set 3 numpad keys 2025-08-19 16:23:30 +03:00
Bananymous 8c9ab2d68c WindowServer: Fix crash when window closes while being "button window" 2025-08-19 16:23:30 +03:00
Bananymous 8496726ab1 Terminal: Ignore some control characters 2025-08-19 16:23:30 +03:00
Bananymous 32d7f429f8 Kernel: Fix default ignored signals
SIGWINCH and SIGCANCEL ended up interrupting functions even when they
were marked as SIG_DFL. Now resizing the userspace terminal emulator
does not get interrupted!
2025-08-19 16:23:30 +03:00
Bananymous 0f52f49188 Terminal: Remove unused code 2025-08-19 16:23:30 +03:00
Bananymous b334259a07 AudioServer: Don't allow client to fully halt audio 2025-08-19 16:23:30 +03:00
Bananymous 74af4e9150 ports/SDL2_mixer: Add MIDI support 2025-08-19 16:23:30 +03:00
Bananymous 8b7790ded2 Kernel: Fix userspace pointer checks
Some syscalls were unconditionally validating optional paramenters which
were allowed to be null pointers
2025-08-19 16:23:30 +03:00
Bananymous 3e97a82af0 Kernel: Allow getgroups with size
This can be used to query the number of groups
2025-08-19 16:23:30 +03:00
Bananymous 0066b20413 Kernel: Fix spinlock leaks with unix sockets 2025-08-19 16:23:30 +03:00
Bananymous 9d6656451a LibC: Make time_t signed integer
Some port like python3 assumes this is the case
2025-08-19 16:23:30 +03:00
Bananymous 32f980e259 Kernel: Fix ACPI namespace lookup for multi segment names 2025-08-19 16:23:30 +03:00
Bananymous ca9361abc1 DynamicLoader: Add support for dladdr 2025-08-19 16:23:30 +03:00
Bananymous 36cb3d56fe LibC: Define Dl_info_t and add stub for dladdr 2025-08-19 16:23:30 +03:00
Bananymous 0bece8a54c Kernel: Add missing ACPI resource header 2025-08-19 16:23:30 +03:00
58 changed files with 1464 additions and 311 deletions

View File

@ -34,4 +34,6 @@ signal_trampoline:
addl $8, %esp
popf
movl (%esp), %esp
ret

View File

@ -59,5 +59,7 @@ signal_trampoline:
addq $16, %rsp
popfq
movq (%rsp), %rsp
// return over red-zone
ret $128

View File

@ -0,0 +1,179 @@
#pragma once
#include <BAN/ByteSpan.h>
#include <BAN/Debug.h>
#include <BAN/Optional.h>
namespace Kernel::ACPI
{
struct ResourceData
{
enum class Type
{
IRQ,
DMA,
IOPort,
FixedIOPort,
FixedDMA,
// TODO: large stuff the stuff :)
};
union {
struct {
uint16_t irq_mask;
union {
struct {
uint8_t edge_triggered : 1;
uint8_t : 2;
uint8_t active_low : 1;
uint8_t shared : 1;
uint8_t wake_capable : 1;
uint8_t : 2;
};
uint8_t raw;
};
} irq;
struct {
uint8_t channel_mask;
union {
struct {
uint8_t type : 2; // 0: 8 bit, 1: 8 and 16 bit, 2: 16 bit only
uint8_t bus_master : 1;
uint8_t : 2;
uint8_t channel_speed : 2; // 0: compatibility, 1: type A, 2: type B, 3: type F
uint8_t : 1;
};
uint8_t raw;
};
} dma;
struct {
uint16_t range_min_base;
uint16_t range_max_base;
uint8_t base_alignment;
uint8_t range_length;
} io_port;
struct {
uint16_t range_base;
uint8_t range_length;
} fixed_io_port;
struct {
uint16_t request_line;
uint16_t channel;
uint8_t transfer_width; // 0: 8 bit, 1: 16 bit, 2: 32 bit, 3: 64 bit, 4: 128 bit
} fixed_dma;
} as;
Type type;
};
class ResourceParser
{
public:
ResourceParser(BAN::ConstByteSpan buffer)
: m_buffer(buffer)
{}
BAN::Optional<ResourceData> get_next()
{
for (;;)
{
if (m_buffer.empty())
return {};
if (m_buffer[0] & 0x80)
{
dprintln("Skipping large resource 0x{2H}", m_buffer[0] & 0x7F);
const uint16_t length = (m_buffer[2] << 8) | m_buffer[1];
if (m_buffer.size() < static_cast<size_t>(3 + length))
return {};
m_buffer = m_buffer.slice(3 + length);
continue;
}
const uint8_t length = m_buffer[0] & 0x07;
if (m_buffer.size() < static_cast<size_t>(1 + length))
return {};
BAN::Optional<ResourceData> result;
switch ((m_buffer[0] >> 3) & 0x0F)
{
case 0x04:
if (length < 2)
break;
result = ResourceData {
.as = { .irq = {
.irq_mask = static_cast<uint16_t>((m_buffer[2] << 8) | m_buffer[1]),
.raw = (length >= 3) ? m_buffer[3] : static_cast<uint8_t>(1),
}},
.type = ResourceData::Type::IRQ,
};
break;
case 0x05:
if (length < 2)
break;
result = ResourceData {
.as = { .dma = {
.channel_mask = m_buffer[1],
.raw = m_buffer[2],
}},
.type = ResourceData::Type::DMA,
};
break;
case 0x08:
if (length < 7)
break;
result = ResourceData {
.as = { .io_port = {
.range_min_base = static_cast<uint16_t>(((m_buffer[3] << 8) | m_buffer[2]) & ((m_buffer[1] & 1) ? 0xFFFF : 0x03FF)),
.range_max_base = static_cast<uint16_t>(((m_buffer[5] << 8) | m_buffer[4]) & ((m_buffer[1] & 1) ? 0xFFFF : 0x03FF)),
.base_alignment = m_buffer[6],
.range_length = m_buffer[7],
}},
.type = ResourceData::Type::IOPort,
};
break;
case 0x09:
if (length < 3)
break;
result = ResourceData {
.as = { .fixed_io_port = {
.range_base = static_cast<uint16_t>(((m_buffer[2] << 8) | m_buffer[1]) & 0x03FF),
.range_length = m_buffer[3],
}},
.type = ResourceData::Type::FixedIOPort,
};
break;
case 0x0A:
if (length < 5)
break;
result = ResourceData {
.as = { .fixed_dma = {
.request_line = static_cast<uint16_t>((m_buffer[2] << 8) | m_buffer[1]),
.channel = static_cast<uint16_t>((m_buffer[4] << 8) | m_buffer[3]),
.transfer_width = m_buffer[5],
}},
.type = ResourceData::Type::FixedDMA,
};
break;
case 0x0F:
// End tag
return {};
case 0x06:
case 0x07:
case 0x0E:
dprintln("Skipping short resource 0x{2H}", (m_buffer[0] >> 3) & 0x0F);
break;
}
m_buffer = m_buffer.slice(1 + length);
if (result.has_value())
return result.release_value();
}
}
private:
BAN::ConstByteSpan m_buffer;
};
}

View File

@ -193,6 +193,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact);
BAN::ErrorOr<long> sys_sigpending(sigset_t* set);
BAN::ErrorOr<long> sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset);
BAN::ErrorOr<long> sys_sigsuspend(const sigset_t* set);
BAN::ErrorOr<long> sys_sigwait(const sigset_t* set, int* sig);
BAN::ErrorOr<long> sys_sigaltstack(const stack_t* ss, stack_t* oss);
BAN::ErrorOr<long> sys_futex(int op, const uint32_t* addr, uint32_t val, const timespec* abstime);
BAN::ErrorOr<long> sys_yield();
@ -347,14 +350,6 @@ namespace Kernel
BAN::UniqPtr<PageTable> m_page_table;
BAN::RefPtr<TTY> m_controlling_terminal;
struct futex_t
{
ThreadBlocker blocker;
uint32_t waiters { 0 };
uint32_t to_wakeup { 0 };
};
BAN::HashMap<paddr_t, BAN::UniqPtr<futex_t>> m_futexes;
friend class Thread;
};

View File

@ -1,6 +1,7 @@
#pragma once
#include <BAN/NoCopyMove.h>
#include <BAN/Optional.h>
#include <BAN/RefPtr.h>
#include <BAN/UniqPtr.h>
#include <kernel/InterruptStack.h>
@ -59,7 +60,10 @@ namespace Kernel
bool will_execute_signal() const;
// Returns true if handled signal had SA_RESTART
bool handle_signal(int signal = 0);
bool add_signal(int signal);
void add_signal(int signal);
void set_suspend_signal_mask(uint64_t sigmask);
BAN::ErrorOr<void> sigaltstack(const stack_t* ss, stack_t* oss);
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout
// if mutex is not nullptr, it will be atomically freed before blocking and automatically locked on wake
@ -138,6 +142,8 @@ namespace Kernel
static void on_exit_trampoline(Thread*);
void on_exit();
bool currently_on_alternate_stack() const;
private:
// NOTE: this is the first member to force it being last destructed
// {kernel,userspace}_stack has to be destroyed before page table
@ -160,7 +166,9 @@ namespace Kernel
uint64_t m_signal_pending_mask { 0 };
uint64_t m_signal_block_mask { 0 };
BAN::Optional<uint64_t> m_signal_suspend_mask;
SpinLock m_signal_lock;
stack_t m_signal_alt_stack { nullptr, 0, SS_DISABLE };
static_assert(_SIGMAX < 64);
mutable SpinLock m_cpu_time_lock;

View File

@ -438,7 +438,7 @@ namespace Kernel::ACPI::AML
{
dprintln_if(AML_DUMP_FUNCTION_CALLS, "find_named_object('{}', '{}')", scope, name_string);
if (force_absolute || name_string.base != 0)
if (force_absolute || name_string.base != 0 || name_string.parts.size() > 1)
{
// Absolute path
@ -460,23 +460,15 @@ namespace Kernel::ACPI::AML
// Relative path
Scope path_guess;
TRY(path_guess.parts.reserve(scope.parts.size() + name_string.parts.size()));
TRY(path_guess.parts.reserve(scope.parts.size() + 1));
const uint32_t name_seg = name_string.parts.front();
for (const auto& part : scope.parts)
TRY(path_guess.parts.push_back(part));
for (const auto& part : name_string.parts)
TRY(path_guess.parts.push_back(part));
TRY(path_guess.parts.push_back(name_seg));
auto it = m_named_objects.find(path_guess);
if (it != m_named_objects.end()) {
return FindResult {
.path = BAN::move(path_guess),
.node = it->value,
};
}
for (size_t i = 0; i < scope.parts.size(); i++)
for (;;)
{
path_guess.parts.remove(scope.parts.size() - i - 1);
auto it = m_named_objects.find(path_guess);
if (it != m_named_objects.end()) {
return FindResult {
@ -484,12 +476,17 @@ namespace Kernel::ACPI::AML
.node = it->value,
};
}
}
return FindResult {
.path = {},
.node = nullptr,
};
if (path_guess.parts.size() == 1) {
return FindResult {
.path = {},
.node = nullptr,
};
}
path_guess.parts.pop_back();
path_guess.parts.back() = name_seg;
}
}
BAN::ErrorOr<Scope> Namespace::find_reference_scope(const Reference* reference)

View File

@ -30,19 +30,19 @@ namespace Kernel
timespec FATInode::atime() const
{
uint64_t epoch = fat_date_to_epoch(m_entry.last_access_date, {});
const time_t epoch = fat_date_to_epoch(m_entry.last_access_date, {});
return timespec { .tv_sec = epoch, .tv_nsec = 0 };
}
timespec FATInode::mtime() const
{
uint64_t epoch = fat_date_to_epoch(m_entry.write_date, m_entry.write_time);
const time_t epoch = fat_date_to_epoch(m_entry.write_date, m_entry.write_time);
return timespec { .tv_sec = epoch, .tv_nsec = 0 };
}
timespec FATInode::ctime() const
{
uint64_t epoch = fat_date_to_epoch(m_entry.creation_date, m_entry.creation_time);
const time_t epoch = fat_date_to_epoch(m_entry.creation_date, m_entry.creation_time);
return timespec { .tv_sec = epoch, .tv_nsec = 0 };
}

View File

@ -256,84 +256,84 @@ namespace Kernel::Input
void PS2Keymap::initialize_scancode_set3()
{
m_scancode_to_keycode_normal[0x0E] = keycode_normal(0, 0);
m_scancode_to_keycode_normal[0x16] = keycode_normal(0, 1);
m_scancode_to_keycode_normal[0x1E] = keycode_normal(0, 2);
m_scancode_to_keycode_normal[0x26] = keycode_normal(0, 3);
m_scancode_to_keycode_normal[0x25] = keycode_normal(0, 4);
m_scancode_to_keycode_normal[0x2E] = keycode_normal(0, 5);
m_scancode_to_keycode_normal[0x36] = keycode_normal(0, 6);
m_scancode_to_keycode_normal[0x3D] = keycode_normal(0, 7);
m_scancode_to_keycode_normal[0x3E] = keycode_normal(0, 8);
m_scancode_to_keycode_normal[0x46] = keycode_normal(0, 9);
m_scancode_to_keycode_normal[0x45] = keycode_normal(0, 10);
m_scancode_to_keycode_normal[0x4E] = keycode_normal(0, 11);
m_scancode_to_keycode_normal[0x55] = keycode_normal(0, 12);
m_scancode_to_keycode_normal[0x66] = keycode_normal(0, 13);
m_scancode_to_keycode_normal[0x0D] = keycode_normal(1, 0);
m_scancode_to_keycode_normal[0x15] = keycode_normal(1, 1);
m_scancode_to_keycode_normal[0x1D] = keycode_normal(1, 2);
m_scancode_to_keycode_normal[0x24] = keycode_normal(1, 3);
m_scancode_to_keycode_normal[0x2D] = keycode_normal(1, 4);
m_scancode_to_keycode_normal[0x2C] = keycode_normal(1, 5);
m_scancode_to_keycode_normal[0x35] = keycode_normal(1, 6);
m_scancode_to_keycode_normal[0x3C] = keycode_normal(1, 7);
m_scancode_to_keycode_normal[0x43] = keycode_normal(1, 8);
m_scancode_to_keycode_normal[0x44] = keycode_normal(1, 9);
m_scancode_to_keycode_normal[0x4D] = keycode_normal(1, 10);
m_scancode_to_keycode_normal[0x54] = keycode_normal(1, 11);
m_scancode_to_keycode_normal[0x5B] = keycode_normal(1, 12);
m_scancode_to_keycode_normal[0x14] = keycode_normal(2, 0);
m_scancode_to_keycode_normal[0x1C] = keycode_normal(2, 1);
m_scancode_to_keycode_normal[0x1B] = keycode_normal(2, 2);
m_scancode_to_keycode_normal[0x23] = keycode_normal(2, 3);
m_scancode_to_keycode_normal[0x2B] = keycode_normal(2, 4);
m_scancode_to_keycode_normal[0x34] = keycode_normal(2, 5);
m_scancode_to_keycode_normal[0x33] = keycode_normal(2, 6);
m_scancode_to_keycode_normal[0x3B] = keycode_normal(2, 7);
m_scancode_to_keycode_normal[0x42] = keycode_normal(2, 8);
m_scancode_to_keycode_normal[0x4B] = keycode_normal(2, 9);
m_scancode_to_keycode_normal[0x4C] = keycode_normal(2, 10);
m_scancode_to_keycode_normal[0x52] = keycode_normal(2, 11);
m_scancode_to_keycode_normal[0x5C] = keycode_normal(2, 12);
m_scancode_to_keycode_normal[0x5A] = keycode_normal(2, 13);
m_scancode_to_keycode_normal[0x12] = keycode_normal(3, 0);
m_scancode_to_keycode_normal[0x13] = keycode_normal(3, 1);
m_scancode_to_keycode_normal[0x1A] = keycode_normal(3, 2);
m_scancode_to_keycode_normal[0x22] = keycode_normal(3, 3);
m_scancode_to_keycode_normal[0x21] = keycode_normal(3, 4);
m_scancode_to_keycode_normal[0x2A] = keycode_normal(3, 5);
m_scancode_to_keycode_normal[0x32] = keycode_normal(3, 6);
m_scancode_to_keycode_normal[0x31] = keycode_normal(3, 7);
m_scancode_to_keycode_normal[0x3A] = keycode_normal(3, 8);
m_scancode_to_keycode_normal[0x41] = keycode_normal(3, 9);
m_scancode_to_keycode_normal[0x49] = keycode_normal(3, 10);
m_scancode_to_keycode_normal[0x4A] = keycode_normal(3, 11);
m_scancode_to_keycode_normal[0x59] = keycode_normal(3, 12);
m_scancode_to_keycode_normal[0x11] = keycode_normal(4, 0);
m_scancode_to_keycode_normal[0x8B] = keycode_normal(4, 1);
m_scancode_to_keycode_normal[0x19] = keycode_normal(4, 2);
m_scancode_to_keycode_normal[0x29] = keycode_normal(4, 3);
m_scancode_to_keycode_normal[0x39] = keycode_normal(4, 4);
m_scancode_to_keycode_normal[0x58] = keycode_normal(4, 5);
m_scancode_to_keycode_normal[0x0E] = keycode_normal(0, 0);
m_scancode_to_keycode_normal[0x16] = keycode_normal(0, 1);
m_scancode_to_keycode_normal[0x1E] = keycode_normal(0, 2);
m_scancode_to_keycode_normal[0x26] = keycode_normal(0, 3);
m_scancode_to_keycode_normal[0x25] = keycode_normal(0, 4);
m_scancode_to_keycode_normal[0x2E] = keycode_normal(0, 5);
m_scancode_to_keycode_normal[0x36] = keycode_normal(0, 6);
m_scancode_to_keycode_normal[0x3D] = keycode_normal(0, 7);
m_scancode_to_keycode_normal[0x3E] = keycode_normal(0, 8);
m_scancode_to_keycode_normal[0x46] = keycode_normal(0, 9);
m_scancode_to_keycode_normal[0x45] = keycode_normal(0, 10);
m_scancode_to_keycode_normal[0x4E] = keycode_normal(0, 11);
m_scancode_to_keycode_normal[0x55] = keycode_normal(0, 12);
m_scancode_to_keycode_normal[0x66] = keycode_normal(0, 13);
m_scancode_to_keycode_normal[0x0D] = keycode_normal(1, 0);
m_scancode_to_keycode_normal[0x15] = keycode_normal(1, 1);
m_scancode_to_keycode_normal[0x1D] = keycode_normal(1, 2);
m_scancode_to_keycode_normal[0x24] = keycode_normal(1, 3);
m_scancode_to_keycode_normal[0x2D] = keycode_normal(1, 4);
m_scancode_to_keycode_normal[0x2C] = keycode_normal(1, 5);
m_scancode_to_keycode_normal[0x35] = keycode_normal(1, 6);
m_scancode_to_keycode_normal[0x3C] = keycode_normal(1, 7);
m_scancode_to_keycode_normal[0x43] = keycode_normal(1, 8);
m_scancode_to_keycode_normal[0x44] = keycode_normal(1, 9);
m_scancode_to_keycode_normal[0x4D] = keycode_normal(1, 10);
m_scancode_to_keycode_normal[0x54] = keycode_normal(1, 11);
m_scancode_to_keycode_normal[0x5B] = keycode_normal(1, 12);
m_scancode_to_keycode_normal[0x14] = keycode_normal(2, 0);
m_scancode_to_keycode_normal[0x1C] = keycode_normal(2, 1);
m_scancode_to_keycode_normal[0x1B] = keycode_normal(2, 2);
m_scancode_to_keycode_normal[0x23] = keycode_normal(2, 3);
m_scancode_to_keycode_normal[0x2B] = keycode_normal(2, 4);
m_scancode_to_keycode_normal[0x34] = keycode_normal(2, 5);
m_scancode_to_keycode_normal[0x33] = keycode_normal(2, 6);
m_scancode_to_keycode_normal[0x3B] = keycode_normal(2, 7);
m_scancode_to_keycode_normal[0x42] = keycode_normal(2, 8);
m_scancode_to_keycode_normal[0x4B] = keycode_normal(2, 9);
m_scancode_to_keycode_normal[0x4C] = keycode_normal(2, 10);
m_scancode_to_keycode_normal[0x52] = keycode_normal(2, 11);
m_scancode_to_keycode_normal[0x5C] = keycode_normal(2, 12);
m_scancode_to_keycode_normal[0x5A] = keycode_normal(2, 13);
m_scancode_to_keycode_normal[0x12] = keycode_normal(3, 0);
m_scancode_to_keycode_normal[0x13] = keycode_normal(3, 1);
m_scancode_to_keycode_normal[0x1A] = keycode_normal(3, 2);
m_scancode_to_keycode_normal[0x22] = keycode_normal(3, 3);
m_scancode_to_keycode_normal[0x21] = keycode_normal(3, 4);
m_scancode_to_keycode_normal[0x2A] = keycode_normal(3, 5);
m_scancode_to_keycode_normal[0x32] = keycode_normal(3, 6);
m_scancode_to_keycode_normal[0x31] = keycode_normal(3, 7);
m_scancode_to_keycode_normal[0x3A] = keycode_normal(3, 8);
m_scancode_to_keycode_normal[0x41] = keycode_normal(3, 9);
m_scancode_to_keycode_normal[0x49] = keycode_normal(3, 10);
m_scancode_to_keycode_normal[0x4A] = keycode_normal(3, 11);
m_scancode_to_keycode_normal[0x59] = keycode_normal(3, 12);
m_scancode_to_keycode_normal[0x11] = keycode_normal(4, 0);
m_scancode_to_keycode_normal[0x8B] = keycode_normal(4, 1);
m_scancode_to_keycode_normal[0x19] = keycode_normal(4, 2);
m_scancode_to_keycode_normal[0x29] = keycode_normal(4, 3);
m_scancode_to_keycode_normal[0x39] = keycode_normal(4, 4);
m_scancode_to_keycode_normal[0x58] = keycode_normal(4, 5);
m_scancode_to_keycode_normal[0x76] = keycode_numpad(0, 0);
//m_scancode_to_keycode_normal[0x] = keycode_numpad(0, 1);
m_scancode_to_keycode_normal[0x4A] = keycode_numpad(0, 1);
m_scancode_to_keycode_normal[0x7E] = keycode_numpad(0, 2);
//m_scancode_to_keycode_normal[0x] = keycode_numpad(0, 3);
m_scancode_to_keycode_normal[0x6C] = keycode_numpad(1, 1);
m_scancode_to_keycode_normal[0x75] = keycode_numpad(1, 2);
m_scancode_to_keycode_normal[0x7D] = keycode_numpad(1, 3);
m_scancode_to_keycode_normal[0x7C] = keycode_numpad(1, 4);
m_scancode_to_keycode_normal[0x6B] = keycode_numpad(2, 1);
m_scancode_to_keycode_normal[0x73] = keycode_numpad(2, 2);
m_scancode_to_keycode_normal[0x74] = keycode_numpad(2, 3);
m_scancode_to_keycode_normal[0x69] = keycode_numpad(3, 1);
m_scancode_to_keycode_normal[0x72] = keycode_numpad(3, 2);
m_scancode_to_keycode_normal[0x7A] = keycode_numpad(3, 3);
m_scancode_to_keycode_normal[0x79] = keycode_numpad(3, 4);
m_scancode_to_keycode_normal[0x70] = keycode_numpad(4, 1);
m_scancode_to_keycode_normal[0x71] = keycode_numpad(4, 2);
m_scancode_to_keycode_normal[0x4E] = keycode_numpad(0, 3);
m_scancode_to_keycode_normal[0x6C] = keycode_numpad(1, 0);
m_scancode_to_keycode_normal[0x75] = keycode_numpad(1, 1);
m_scancode_to_keycode_normal[0x7D] = keycode_numpad(1, 2);
m_scancode_to_keycode_normal[0x7C] = keycode_numpad(1, 3);
m_scancode_to_keycode_normal[0x6B] = keycode_numpad(2, 0);
m_scancode_to_keycode_normal[0x73] = keycode_numpad(2, 1);
m_scancode_to_keycode_normal[0x74] = keycode_numpad(2, 2);
m_scancode_to_keycode_normal[0x69] = keycode_numpad(3, 0);
m_scancode_to_keycode_normal[0x72] = keycode_numpad(3, 1);
m_scancode_to_keycode_normal[0x7A] = keycode_numpad(3, 2);
m_scancode_to_keycode_normal[0x79] = keycode_numpad(3, 3);
m_scancode_to_keycode_normal[0x70] = keycode_numpad(4, 0);
m_scancode_to_keycode_normal[0x71] = keycode_numpad(4, 1);
m_scancode_to_keycode_normal[0x08] = keycode_function(0);
m_scancode_to_keycode_normal[0x07] = keycode_function(1);

View File

@ -289,10 +289,10 @@ namespace Kernel
BAN::ErrorOr<void> UnixDomainSocket::add_packet(BAN::ConstByteSpan packet)
{
auto state = m_packet_lock.lock();
SpinLockGuard guard(m_packet_lock);
while (m_packet_sizes.full() || m_packet_size_total + packet.size() > s_packet_buffer_size)
{
SpinLockAsMutex smutex(m_packet_lock, state);
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &smutex));
}
@ -304,7 +304,6 @@ namespace Kernel
m_packet_sizes.push(packet.size());
m_packet_thread_blocker.unblock();
m_packet_lock.unlock(state);
epoll_notify(EPOLLIN);
@ -414,7 +413,7 @@ namespace Kernel
BAN::ErrorOr<size_t> UnixDomainSocket::recvfrom_impl(BAN::ByteSpan buffer, sockaddr*, socklen_t*)
{
auto state = m_packet_lock.lock();
SpinLockGuard guard(m_packet_lock);
while (m_packet_size_total == 0)
{
if (m_info.has<ConnectionInfo>())
@ -422,18 +421,12 @@ namespace Kernel
auto& connection_info = m_info.get<ConnectionInfo>();
bool expected = true;
if (connection_info.target_closed.compare_exchange(expected, false))
{
m_packet_lock.unlock(state);
return 0;
}
if (!connection_info.connection)
{
m_packet_lock.unlock(state);
return BAN::Error::from_errno(ENOTCONN);
}
}
SpinLockAsMutex smutex(m_packet_lock, state);
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &smutex));
}
@ -453,7 +446,6 @@ namespace Kernel
m_packet_size_total -= nread;
m_packet_thread_blocker.unblock();
m_packet_lock.unlock(state);
epoll_notify(EPOLLOUT);

View File

@ -37,6 +37,15 @@ namespace Kernel
static BAN::Vector<Process*> s_processes;
static RecursiveSpinLock s_process_lock;
struct futex_t
{
ThreadBlocker blocker;
uint32_t waiters { 0 };
uint32_t to_wakeup { 0 };
};
static BAN::HashMap<paddr_t, BAN::UniqPtr<futex_t>> s_futexes;
static Mutex s_futex_lock;
static void for_each_process(const BAN::Function<BAN::Iteration(Process&)>& callback)
{
SpinLockGuard _(s_process_lock);
@ -309,7 +318,7 @@ namespace Kernel
LockGuard _(m_process_lock);
for (auto* thread : m_threads)
if (thread != &Thread::current())
ASSERT(thread->add_signal(SIGKILL));
thread->add_signal(SIGKILL);
}
while (m_threads.size() > 1)
@ -1158,8 +1167,10 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_hardlinkat(int fd1, const char* path1, int fd2, const char* path2, int flag)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path1));
TRY(validate_string_access(path2));
if (path1 != nullptr)
TRY(validate_string_access(path1));
if (path2 != nullptr)
TRY(validate_string_access(path2));
auto inode = TRY(find_file(fd1, path1, flag)).inode;
if (inode->mode().ifdir())
@ -1180,7 +1191,8 @@ namespace Kernel
return BAN::Error::from_errno(EINVAL);
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
if (path != nullptr)
TRY(validate_string_access(path));
auto [parent, file_name] = TRY(find_parent_file(fd, path, O_WRONLY));
@ -1195,7 +1207,8 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
if (path != nullptr)
TRY(validate_string_access(path));
TRY(validate_pointer_access(buffer, bufsize, true));
auto inode = TRY(find_file(fd, path, O_NOFOLLOW | O_RDONLY)).inode;
@ -1262,7 +1275,8 @@ namespace Kernel
flag = O_NOFOLLOW;
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
if (path != nullptr)
TRY(validate_string_access(path));
auto inode = TRY(find_file(fd, path, flag)).inode;
@ -1285,7 +1299,8 @@ namespace Kernel
flag = O_NOFOLLOW;
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
if (path != nullptr)
TRY(validate_string_access(path));
auto inode = TRY(find_file(fd, path, flag)).inode;
@ -1971,6 +1986,8 @@ namespace Kernel
flag = O_NOFOLLOW;
LockGuard _(m_process_lock);
if (path != nullptr)
TRY(validate_string_access(path));
TRY(validate_pointer_access(buf, sizeof(struct stat), true));
auto inode = TRY(find_file(fd, path, flag)).inode;
@ -1994,6 +2011,8 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_fstatvfsat(int fd, const char* path, struct statvfs* buf)
{
LockGuard _(m_process_lock);
if (path != nullptr)
TRY(validate_string_access(path));
TRY(validate_pointer_access(buf, sizeof(struct statvfs), true));
auto inode = TRY(find_file(fd, path, 0)).inode;
@ -2158,6 +2177,17 @@ namespace Kernel
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;
for (size_t i = 0; i < m_mapped_regions.size(); i++)
{
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");
m_mapped_regions[i]->wait_not_pinned();
m_mapped_regions.remove(i--);
}
}
if (args.flags & MAP_ANONYMOUS)
@ -2641,23 +2671,81 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_sigsuspend(const sigset_t* set)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(set, sizeof(sigset_t), false));
auto& thread = Thread::current();
thread.set_suspend_signal_mask(*set & ~(SIGKILL | SIGSTOP));
while (!thread.is_interrupted_by_signal())
Processor::scheduler().block_current_thread(nullptr, -1, &m_process_lock);
return BAN::Error::from_errno(EINTR);
}
BAN::ErrorOr<long> Process::sys_sigwait(const sigset_t* set, int* sig)
{
LockGuard _(m_process_lock);
auto& thread = Thread::current();
for (;;)
{
TRY(validate_pointer_access(set, sizeof(sigset_t), false));
TRY(validate_pointer_access(sig, sizeof(int), true));
{
SpinLockGuard _1(thread.m_signal_lock);
SpinLockGuard _2(m_signal_lock);
const uint64_t pending = thread.m_signal_pending_mask | this->m_signal_pending_mask;
if (const auto wait_mask = pending & *set)
{
for (size_t i = _SIGMIN; i <= _SIGMAX; i++)
{
const auto mask = 1ull << i;
if (!(wait_mask & mask))
continue;
thread.m_signal_pending_mask &= ~mask;
this->m_signal_pending_mask &= ~mask;
*sig = i;
return 0;
}
ASSERT_NOT_REACHED();
}
}
Processor::scheduler().block_current_thread(nullptr, -1, &m_process_lock);
}
}
BAN::ErrorOr<long> Process::sys_sigaltstack(const stack_t* ss, stack_t* oss)
{
LockGuard _(m_process_lock);
if (ss != nullptr)
TRY(validate_pointer_access(ss, sizeof(stack_t), false));
if (oss != nullptr)
TRY(validate_pointer_access(oss, sizeof(stack_t), true));
TRY(Thread::current().sigaltstack(ss, oss));
return 0;
}
BAN::ErrorOr<long> Process::sys_futex(int op, const uint32_t* addr, uint32_t val, const timespec* abstime)
{
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(addr);
if (vaddr % 4)
return BAN::Error::from_errno(EINVAL);
const bool is_private = (op & FUTEX_PRIVATE);
const bool is_realtime = (op & FUTEX_REALTIME);
op &= ~(FUTEX_PRIVATE | FUTEX_REALTIME);
if (!is_private)
{
dwarnln("TODO: shared futex");
return BAN::Error::from_errno(ENOTSUP);
}
// TODO: possibly optimize private futexes?
LockGuard _(m_process_lock);
LockGuard _(s_futex_lock);
auto* buffer_region = TRY(validate_and_pin_pointer_access(addr, sizeof(uint32_t), false));
BAN::ScopeGuard pin_guard([&] { if (buffer_region) buffer_region->unpin(); });
@ -2688,20 +2776,20 @@ namespace Kernel
return SystemTimer::get().ns_since_boot() + (abs_ns - real_ns);
}());
auto it = m_futexes.find(paddr);
if (it == m_futexes.end())
it = TRY(m_futexes.emplace(paddr, TRY(BAN::UniqPtr<futex_t>::create())));
auto it = s_futexes.find(paddr);
if (it == s_futexes.end())
it = TRY(s_futexes.emplace(paddr, TRY(BAN::UniqPtr<futex_t>::create())));
futex_t* const futex = it->value.ptr();
futex->waiters++;
BAN::ScopeGuard _([futex, paddr, this] {
BAN::ScopeGuard _([futex, paddr] {
if (--futex->waiters == 0)
m_futexes.remove(paddr);
s_futexes.remove(paddr);
});
for (;;)
{
TRY(Thread::current().block_or_eintr_or_waketime_ns(futex->blocker, wake_time_ns, true, &m_process_lock));
TRY(Thread::current().block_or_eintr_or_waketime_ns(futex->blocker, wake_time_ns, true, &s_futex_lock));
if (BAN::atomic_load(*addr) == val || futex->to_wakeup == 0)
continue;
futex->to_wakeup--;
@ -2710,8 +2798,8 @@ namespace Kernel
}
case FUTEX_WAKE:
{
auto it = m_futexes.find(paddr);
if (it == m_futexes.end())
auto it = s_futexes.find(paddr);
if (it == s_futexes.end())
return 0;
futex_t* const futex = it->value.ptr();
@ -3211,8 +3299,10 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_getgroups(gid_t groups[], size_t count)
{
LockGuard _(m_process_lock);
const auto current = m_credentials.groups();
if (count == 0)
return current.size();
TRY(validate_pointer_access(groups, count * sizeof(gid_t), true));
auto current = m_credentials.groups();
if (current.size() > count)
return BAN::Error::from_errno(EINVAL);
for (size_t i = 0; i < current.size(); i++)
@ -3295,6 +3385,9 @@ unauthorized_access:
{
// 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);

View File

@ -92,14 +92,14 @@ namespace Kernel
if (ret.is_error() && ret.error().is_kernel_error())
Kernel::panic("Kernel error while returning to userspace {}", ret.error());
Processor::set_interrupt_state(InterruptState::Disabled);
auto& current_thread = Thread::current();
if (current_thread.can_add_signal_to_execute())
if (current_thread.handle_signal())
if (ret.is_error() && ret.error().get_error_code() == EINTR && is_restartable_syscall(syscall))
ret = BAN::Error::from_errno(ERESTART);
Processor::set_interrupt_state(InterruptState::Disabled);
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
if (ret.is_error())

View File

@ -165,7 +165,7 @@ namespace Kernel
PseudoTerminalSlave::PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t mode, uid_t uid, gid_t gid)
: TTY({
.c_iflag = 0,
.c_iflag = ICRNL,
.c_oflag = 0,
.c_cflag = CS8,
.c_lflag = ECHO | ECHOE | ECHOK | ICANON | ISIG,

View File

@ -243,19 +243,14 @@ namespace Kernel
LockGuard _(m_mutex);
if (m_termios.c_lflag & ICANON)
{
if ((m_termios.c_iflag & ISTRIP))
ch &= 0x7F;
if ((m_termios.c_iflag & IGNCR) && ch == CR)
return;
uint8_t conv = ch;
if ((m_termios.c_iflag & ICRNL) && ch == CR)
conv = NL;
if ((m_termios.c_iflag & INLCR) && ch == NL)
conv = CR;
ch = conv;
}
if ((m_termios.c_iflag & ISTRIP))
ch &= 0x7F;
if ((m_termios.c_iflag & IGNCR) && ch == CR)
return;
if ((m_termios.c_iflag & ICRNL) && ch == CR)
ch = NL;
else if ((m_termios.c_iflag & INLCR) && ch == NL)
ch = CR;
if (m_termios.c_lflag & ISIG)
{
@ -298,11 +293,10 @@ namespace Kernel
should_flush = true;
}
if (ch == NL || ch == m_termios.c_cc[VEOL])
if (ch == NL || ch == CR || ch == m_termios.c_cc[VEOL])
{
should_flush = true;
force_echo = !!(m_termios.c_lflag & ECHONL);
ch = NL;
}
}

View File

@ -37,7 +37,7 @@ namespace Kernel
VirtualTTY::VirtualTTY(BAN::RefPtr<TerminalDriver> driver)
: TTY({
.c_iflag = 0,
.c_iflag = ICRNL,
.c_oflag = 0,
.c_cflag = CS8,
.c_lflag = ECHO | ECHOE | ECHOK | ICANON | ISIG,

View File

@ -69,6 +69,20 @@ namespace Kernel
s_default_sse_storage_initialized = true;
}
static bool is_default_ignored_signal(int signal)
{
switch (signal)
{
case SIGCHLD:
case SIGURG:
case SIGWINCH:
case SIGCANCEL:
return true;
default:
return false;
}
}
BAN::ErrorOr<Thread*> Thread::create_kernel(entry_t entry, void* data)
{
// Create the thread object
@ -467,7 +481,7 @@ namespace Kernel
}
if (signal_handler == (vaddr_t)SIG_IGN)
continue;
if (signal_handler == (vaddr_t)SIG_DFL && (i == SIGCHLD || i == SIGURG))
if (signal_handler == (vaddr_t)SIG_DFL && is_default_ignored_signal(i))
continue;
return true;
}
@ -493,6 +507,7 @@ namespace Kernel
ASSERT(is_userspace());
auto state = m_signal_lock.lock();
ASSERT(state == InterruptState::Disabled);
auto& interrupt_stack = *reinterpret_cast<InterruptStack*>(kernel_stack_top() - sizeof(InterruptStack));
ASSERT(GDT::is_user_segment(interrupt_stack.cs));
@ -516,6 +531,7 @@ namespace Kernel
vaddr_t signal_handler;
bool has_sa_restart;
vaddr_t signal_stack_top = 0;
{
SpinLockGuard _(m_process->m_signal_lock);
@ -528,11 +544,23 @@ namespace Kernel
handler.sa_handler = SIG_DFL;
has_sa_restart = !!(handler.sa_flags & SA_RESTART);
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;
}
m_signal_pending_mask &= ~(1ull << signal);
process().remove_pending_signal(signal);
if (m_signal_suspend_mask.has_value())
{
m_signal_block_mask = m_signal_suspend_mask.value();
m_signal_suspend_mask.clear();
}
m_signal_lock.unlock(state);
if (signal_handler == (vaddr_t)SIG_IGN)
;
else if (signal_handler != (vaddr_t)SIG_DFL)
@ -541,7 +569,32 @@ namespace Kernel
#if ARCH(x86_64)
interrupt_stack.sp -= 128; // skip possible red-zone
#endif
{
// Make sure stack is allocated
const vaddr_t pages[3] {
(interrupt_stack.sp - sizeof(uintptr_t)) & PAGE_ADDR_MASK,
(signal_stack_top - 4 * sizeof(uintptr_t)) & PAGE_ADDR_MASK,
(signal_stack_top - 1 * sizeof(uintptr_t)) & PAGE_ADDR_MASK,
};
for (size_t i = 0; i < 3; i++)
{
if (m_process->page_table().get_page_flags(pages[i]) & PageTable::Flags::Present)
continue;
Processor::set_interrupt_state(InterruptState::Enabled);
if (auto ret = m_process->allocate_page_for_demand_paging(pages[i], true, false); ret.is_error() || !ret.value())
m_process->exit(128 + SIGSEGV, SIGSEGV);
Processor::set_interrupt_state(InterruptState::Disabled);
}
}
write_to_stack(interrupt_stack.sp, interrupt_stack.ip);
const vaddr_t old_stack = interrupt_stack.sp;
if (signal_stack_top)
interrupt_stack.sp = signal_stack_top;
write_to_stack(interrupt_stack.sp, old_stack);
write_to_stack(interrupt_stack.sp, interrupt_stack.flags);
write_to_stack(interrupt_stack.sp, signal);
write_to_stack(interrupt_stack.sp, signal_handler);
@ -562,7 +615,6 @@ namespace Kernel
case SIGTRAP:
case SIGXCPU:
case SIGXFSZ:
m_signal_lock.unlock(state);
process().exit(128 + signal, signal | 0x80);
ASSERT_NOT_REACHED();
@ -578,18 +630,11 @@ namespace Kernel
case SIGPOLL:
case SIGPROF:
case SIGVTALRM:
m_signal_lock.unlock(state);
process().exit(128 + signal, signal);
ASSERT_NOT_REACHED();
// Ignore the signal
case SIGCHLD:
case SIGURG:
case SIGWINCH:
case SIGCANCEL:
break;
// Stop the process:
case SIGSTOP:
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
@ -598,15 +643,18 @@ namespace Kernel
// Continue the process, if it is stopped; otherwise, ignore the signal.
case SIGCONT:
ASSERT_NOT_REACHED();
default:
if (is_default_ignored_signal(signal))
break;
panic("Executing unhandled signal {}", signal);
}
}
m_signal_lock.unlock(state);
return has_sa_restart;
}
bool Thread::add_signal(int signal)
void Thread::add_signal(int signal)
{
SpinLockGuard _(m_signal_lock);
if (m_process)
@ -618,19 +666,64 @@ namespace Kernel
signal_handler = (vaddr_t)m_process->m_signal_handlers[signal].sa_handler;
}
if (signal_handler == (vaddr_t)SIG_IGN)
return false;
if (signal_handler == (vaddr_t)SIG_DFL && (signal == SIGCHLD || signal == SIGURG))
return false;
return;
if (signal_handler == (vaddr_t)SIG_DFL && is_default_ignored_signal(signal))
return;
}
uint64_t mask = 1ull << signal;
if (!(m_signal_block_mask & mask))
const uint64_t mask = 1ull << signal;
m_signal_pending_mask |= mask;
if (this != &Thread::current())
Processor::scheduler().unblock_thread(this);
}
void Thread::set_suspend_signal_mask(uint64_t sigmask)
{
SpinLockGuard _(m_signal_lock);
ASSERT(!m_signal_suspend_mask.has_value());
m_signal_suspend_mask = m_signal_block_mask;
m_signal_block_mask = sigmask;
}
bool Thread::currently_on_alternate_stack() const
{
ASSERT(m_signal_lock.current_processor_has_lock());
if (m_signal_alt_stack.ss_flags == SS_ONSTACK)
return false;
const vaddr_t stack_bottom = reinterpret_cast<vaddr_t>(m_signal_alt_stack.ss_sp);
const vaddr_t stack_top = stack_bottom + m_signal_alt_stack.ss_size;
const vaddr_t sp = m_interrupt_stack.sp;
return stack_bottom <= sp && sp <= stack_top;
}
BAN::ErrorOr<void> Thread::sigaltstack(const stack_t* ss, stack_t* oss)
{
SpinLockGuard _(m_signal_lock);
const bool on_alt_stack = currently_on_alternate_stack();
if (oss)
{
m_signal_pending_mask |= mask;
if (this != &Thread::current())
Processor::scheduler().unblock_thread(this);
return true;
*oss = m_signal_alt_stack;
if (on_alt_stack)
oss->ss_flags = SS_ONSTACK;
}
return false;
if (ss)
{
if (on_alt_stack)
return BAN::Error::from_errno(EPERM);
if (ss->ss_flags && ss->ss_flags != SS_DISABLE)
return BAN::Error::from_errno(EINVAL);
if (ss->ss_size < MINSIGSTKSZ)
return BAN::Error::from_errno(ENOMEM);
m_signal_alt_stack = *ss;
}
return {};
}
BAN::ErrorOr<void> Thread::sleep_or_eintr_ns(uint64_t ns)

View File

@ -299,7 +299,7 @@ namespace Kernel
long ns_this_second = ticks_this_second * regs.counter_clk_period / FS_PER_NS;
return timespec {
.tv_sec = seconds,
.tv_sec = static_cast<time_t>(seconds),
.tv_nsec = ns_this_second
};
}

View File

@ -487,8 +487,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-06 02:01:21.086666679 +0300
@@ -0,0 +1,718 @@
+++ 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 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
@ -894,6 +894,12 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp SDL2-2.32.8-bana
+ }
+ );
+
+ ban_window->window->set_window_focus_event_callback(
+ [window](LibGUI::EventPacket::WindowFocusEvent::event_t event) {
+ SDL_SetKeyboardFocus(event.focused ? window : nullptr);
+ }
+ );
+
+ ban_window->window->set_close_window_event_callback(
+ [window]() {
+ SDL_SendWindowEvent(window, SDL_WINDOWEVENT_CLOSE, 0, 0);

View File

@ -3,15 +3,16 @@
NAME='SDL2_mixer'
VERSION='2.8.1'
DOWNLOAD_URL="https://github.com/libsdl-org/SDL_mixer/releases/download/release-$VERSION/SDL2_mixer-$VERSION.tar.gz#cb760211b056bfe44f4a1e180cc7cb201137e4d1572f2002cc1be728efd22660"
DEPENDENCIES=('SDL2')
DEPENDENCIES=('SDL2' 'timidity')
configure() {
$BANAN_CMAKE --fresh -S . -B build -G Ninja \
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
-DCMAKE_INSTALL_PREFIX='/usr' \
-DCMAKE_BUILD_TYPE=Release \
-DSDL2MIXER_DEPS_SHARED=OFF \
-DSDL2MIXER_MIDI_FLUIDSYNTH=OFF \
-DSDL2MIXER_WAVPACK=OFF \
-DSDL2MIXER_MIDI=OFF \
-DSDL2MIXER_OPUS=OFF \
-DSDL2MIXER_MOD=OFF \
|| exit 1

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

@ -0,0 +1,26 @@
#!/bin/bash ../install.sh
NAME='glib'
VERSION='2.85.2'
DOWNLOAD_URL="https://download.gnome.org/sources/glib/${VERSION%.*}/glib-$VERSION.tar.xz#833b97c0f0a1bfdba1d0fbfc36cd368b855c5afd9f02b8ffb24129114ad051b2"
DEPENDENCIES=('pcre2' 'libffi' 'zlib' 'libiconv')
CONFIGURE_OPTIONS=(
'-Dprefix=/usr'
'-Dxattr=false'
)
configure() {
meson setup \
--reconfigure \
--cross-file "$MESON_CROSS_FILE" \
"${CONFIGURE_OPTIONS[@]}" \
build || exit 1
}
build() {
meson compile -C build || exit 1
}
install() {
meson install --destdir="$BANAN_SYSROOT" -C build || exit 1
}

View File

@ -0,0 +1,106 @@
diff -ruN glib-2.85.2/gio/gnetworking.h.in glib-2.85.2-banan_os/gio/gnetworking.h.in
--- glib-2.85.2/gio/gnetworking.h.in 2025-07-21 20:47:53.000000000 +0300
+++ glib-2.85.2-banan_os/gio/gnetworking.h.in 2025-08-19 18:21:06.038296386 +0300
@@ -40,13 +40,17 @@
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#ifndef __banan_os__
#include <resolv.h>
+#endif
#include <sys/socket.h>
#include <sys/un.h>
#include <net/if.h>
#include <arpa/inet.h>
+#ifndef __banan_os__
#include <arpa/nameser.h>
+#endif
@NAMESER_COMPAT_INCLUDE@
#ifndef __GI_SCANNER__
diff -ruN glib-2.85.2/gio/gthreadedresolver.c glib-2.85.2-banan_os/gio/gthreadedresolver.c
--- glib-2.85.2/gio/gthreadedresolver.c 2025-07-21 20:47:53.000000000 +0300
+++ glib-2.85.2-banan_os/gio/gthreadedresolver.c 2025-08-19 18:21:06.052332130 +0300
@@ -41,6 +41,10 @@
#include "gsocketaddress.h"
#include "gsrvtarget.h"
+#if defined __banan_os__
+#include <endian.h>
+#endif
+
#if HAVE_GETIFADDRS
#include <ifaddrs.h>
#endif
@@ -692,7 +696,7 @@
#if defined(G_OS_UNIX)
-#if defined __BIONIC__ && !defined BIND_4_COMPAT
+#if (defined __BIONIC__ && !defined BIND_4_COMPAT) || defined __banan_os__
/* Copy from bionic/libc/private/arpa_nameser_compat.h
* and bionic/libc/private/arpa_nameser.h */
typedef struct {
@@ -763,6 +767,14 @@
#define dn_skipname __dn_skipname
int dn_skipname(const u_char *, const u_char *);
+#if defined __banan_os__
+#warning "TODO: dn_expand"
+int dn_expand(const u_char *, const u_char *, const u_char *, char *, int)
+{
+ return -1;
+}
+#endif
+
/* From bionic/libc/private/arpa_nameser_compat.h */
#define T_MX ns_t_mx
#define T_TXT ns_t_txt
@@ -1369,7 +1381,7 @@
}
#if defined(G_OS_UNIX)
-#ifdef __BIONIC__
+#if defined __BIONIC__
#ifndef C_IN
#define C_IN 1
#endif
@@ -1420,6 +1432,9 @@
g_byte_array_set_size (answer, len * 2);
#if defined(HAVE_RES_NQUERY)
len = res_nquery (&res, rrname, C_IN, rrtype, answer->data, answer->len);
+#elif defined __banan_os__
+#warning "TODO: res_query"
+ len = -1;
#else
len = res_query (rrname, C_IN, rrtype, answer->data, answer->len);
#endif
diff -ruN glib-2.85.2/gio/meson.build glib-2.85.2-banan_os/gio/meson.build
--- glib-2.85.2/gio/meson.build 2025-07-21 20:47:53.000000000 +0300
+++ glib-2.85.2-banan_os/gio/meson.build 2025-08-19 18:21:06.062294634 +0300
@@ -18,7 +18,7 @@
gnetworking_h_nameser_compat_include = ''
-if host_system not in ['windows', 'android']
+if host_system not in ['windows', 'android', 'banan_os']
# Don't check for C_IN on Android since it does not define it in public
# headers, we define it ourselves wherever necessary
if not cc.compiles('''#include <sys/types.h>
@@ -40,6 +40,7 @@
network_libs = [ ]
network_args = [ ]
if host_system != 'windows'
+ if host_system != 'banan_os'
# res_query()
res_query_test = '''#include <resolv.h>
int main (int argc, char ** argv) {
@@ -63,6 +64,7 @@
error('Could not find res_query()')
endif
endif
+ endif
# socket()
socket_test = '''#include <sys/types.h>

View File

@ -0,0 +1,39 @@
diff -ruN glib-2.85.2/gio/gunixmounts.c glib-2.85.2-banan_os/gio/gunixmounts.c
--- glib-2.85.2/gio/gunixmounts.c 2025-07-21 20:47:53.000000000 +0300
+++ glib-2.85.2-banan_os/gio/gunixmounts.c 2025-08-19 18:21:06.055332112 +0300
@@ -1114,7 +1114,7 @@
}
/* QNX {{{2 */
-#elif defined (HAVE_QNX)
+#elif defined (HAVE_QNX) || defined (__banan_os__)
static char *
get_mtab_monitor_file (void)
@@ -1754,6 +1754,26 @@
if (time_read_out != NULL)
*time_read_out = 0;
if (n_points_out != NULL)
+ *n_points_out = 0;
+ return NULL;
+}
+
+#elif defined (__banan_os__)
+
+static GList *
+_g_get_unix_mount_points (void)
+{
+ return NULL;
+}
+
+static GUnixMountPoint **
+_g_unix_mount_points_get_from_file (const char *table_path,
+ uint64_t *time_read_out,
+ size_t *n_points_out)
+{
+ if (time_read_out != NULL)
+ *time_read_out = 0;
+ if (n_points_out != NULL)
*n_points_out = 0;
return NULL;
}

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

@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
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

@ -0,0 +1,48 @@
diff -ruN libffi-3.5.2/configure libffi-3.5.2-banan_os/configure
--- libffi-3.5.2/configure 2025-08-02 09:44:34.000000000 +0300
+++ libffi-3.5.2-banan_os/configure 2025-08-08 18:24:29.271963294 +0300
@@ -7432,6 +7432,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
;;
@@ -12978,6 +12982,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"
@@ -17612,6 +17626,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"

14
ports/nano/build.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash ../install.sh
NAME='nano'
VERSION='8.5'
DOWNLOAD_URL="https://www.nano-editor.org/dist/v8/nano-$VERSION.tar.xz#000b011d339c141af9646d43288f54325ff5c6e8d39d6e482b787bbc6654c26a"
DEPENDENCIES=('ncurses')
CONFIG_SUB=('config.sub')
CONFIGURE_OPTIONS=(
'ac_cv_header_glob_h=no'
)
pre_configure() {
echo '#include_next <sys/types.h>' > lib/sys_types.in.h
}

View File

@ -0,0 +1,21 @@
diff -ruN nano-8.5/lib/getprogname.c nano-8.5-banan_os/lib/getprogname.c
--- nano-8.5/lib/getprogname.c 2025-06-12 10:29:39.000000000 +0300
+++ nano-8.5-banan_os/lib/getprogname.c 2025-08-19 01:25:56.020428849 +0300
@@ -50,7 +50,7 @@
# include <sys/procfs.h>
#endif
-#if defined __SCO_VERSION__ || defined __sysv5__
+#if defined __SCO_VERSION__ || defined __sysv5__ || defined __banan_os__
# include <fcntl.h>
# include <string.h>
#endif
@@ -265,7 +265,7 @@
}
}
return NULL;
-# elif defined __SCO_VERSION__ || defined __sysv5__ /* SCO OpenServer6/UnixWare */
+# elif defined __SCO_VERSION__ || defined __sysv5__ || defined __banan_os__ /* SCO OpenServer6/UnixWare */
char buf[80];
int fd;
sprintf (buf, "/proc/%d/cmdline", getpid());

13
ports/nyancat/build.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash ../install.sh
NAME='nyancat'
VERSION='git'
DOWNLOAD_URL="https://github.com/klange/nyancat.git#1.5.2"
configure() {
:
}
install() {
cp src/nyancat "$BANAN_SYSROOT/usr/bin/"
}

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

@ -0,0 +1,12 @@
#!/bin/bash ../install.sh
NAME='pcre2'
VERSION='10.45'
DOWNLOAD_URL="https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$VERSION/pcre2-$VERSION.tar.gz#0e138387df7835d7403b8351e2226c1377da804e0737db0e071b48f07c9d12ee"
CONFIG_SUB=('config.sub')
post_install() {
# remove libtool files
rm -f $BANAN_SYSROOT/usr/lib/libpcre2-8.la
rm -f $BANAN_SYSROOT/usr/lib/libpcre2-posix.la
}

View File

@ -0,0 +1,31 @@
diff -ruN pcre2-10.45/configure pcre2-10.45-banan_os/configure
--- pcre2-10.45/configure 2025-02-04 15:48:33.000000000 +0200
+++ pcre2-10.45-banan_os/configure 2025-08-08 00:22:52.975889591 +0300
@@ -6536,6 +6536,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
;;
@@ -12197,6 +12201,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"

17
ports/qemu/build.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/bash ../install.sh
NAME='qemu'
VERSION='10.0.2'
DOWNLOAD_URL="https://download.qemu.org/qemu-$VERSION.tar.xz#ef786f2398cb5184600f69aef4d5d691efd44576a3cff4126d38d4c6fec87759"
DEPENDENCIES=('glib' 'SDL2')
MAKE_BUILD_TARGETS=('qemu-system-x86_64')
CONFIGURE_OPTIONS=(
'--cross-prefix='
'--target-list=x86_64-softmmu'
'--disable-tpm'
'--disable-docs'
)
pre_configure() {
echo '' > tests/meson.build
}

View File

@ -0,0 +1,12 @@
diff -ruN qemu-10.0.2/configure qemu-10.0.2-banan_os/configure
--- qemu-10.0.2/configure 2025-05-29 01:05:46.000000000 +0300
+++ qemu-10.0.2-banan_os/configure 2025-05-31 00:03:10.361102831 +0300
@@ -360,6 +360,8 @@
host_os=netbsd
elif check_define __APPLE__; then
host_os=darwin
+elif check_define __banan_os__; then
+ host_os=banan_os
else
# This is a fatal error, but don't report it yet, because we
# might be going to just print the --help text, or it might

View File

@ -0,0 +1,43 @@
diff -ru qemu-10.0.2/util/oslib-posix.c qemu-10.0.2-x86_64/util/oslib-posix.c
--- qemu-10.0.2/util/oslib-posix.c 2025-05-29 01:05:47.000000000 +0300
+++ qemu-10.0.2-x86_64/util/oslib-posix.c 2025-08-18 02:38:04.839116456 +0300
@@ -128,7 +128,39 @@
int qemu_daemon(int nochdir, int noclose)
{
+#if defined(__banan_os__)
+ const pid_t pid = fork();
+ if (pid == -1) {
+ return -1;
+ }
+ if (pid > 0) {
+ exit(0);
+ }
+
+ if (setsid() == -1) {
+ return -1;
+ }
+
+ if (nochdir == 0) {
+ if (chdir("/") == -1) {
+ return -1;
+ }
+ }
+
+ if (noclose == 0) {
+ int fd = open("/dev/null", O_RDWR);
+ if (fd == -1) {
+ return -1;
+ }
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ }
+
+ return 0;
+#else
return daemon(nochdir, noclose);
+#endif
}
bool qemu_write_pidfile(const char *path, Error **errp)

View File

@ -0,0 +1,24 @@
diff -ru qemu-10.0.2/util/main-loop.c qemu-10.0.2-x86_64/util/main-loop.c
--- qemu-10.0.2/util/main-loop.c 2025-05-29 01:05:47.000000000 +0300
+++ qemu-10.0.2-x86_64/util/main-loop.c 2025-08-09 18:35:25.670990547 +0300
@@ -95,8 +95,10 @@
* not catch it reliably.
*/
sigemptyset(&set);
+#if !defined(__banan_os__)
sigaddset(&set, SIG_IPI);
sigaddset(&set, SIGIO);
+#endif
sigaddset(&set, SIGALRM);
sigaddset(&set, SIGBUS);
/* SIGINT cannot be handled via signalfd, so that ^C can be used
@@ -106,7 +108,9 @@
*/
pthread_sigmask(SIG_BLOCK, &set, NULL);
+#if !defined(__banan_os__)
sigdelset(&set, SIG_IPI);
+#endif
sigfd = qemu_signalfd(&set);
if (sigfd == -1) {
error_setg_errno(errp, errno, "failed to create signalfd");

View File

@ -0,0 +1,22 @@
diff -ru qemu-10.0.2/net/colo.c qemu-10.0.2-x86_64/net/colo.c
--- qemu-10.0.2/net/colo.c 2025-05-29 01:05:46.000000000 +0300
+++ qemu-10.0.2-x86_64/net/colo.c 2025-08-09 19:24:57.624758915 +0300
@@ -123,14 +123,18 @@
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_DCCP:
+#if !defined(__banan_os__)
case IPPROTO_ESP:
+#endif
case IPPROTO_SCTP:
case IPPROTO_UDPLITE:
tmp_ports = *(uint32_t *)(pkt->transport_header);
break;
+#if !defined(__banan_os__)
case IPPROTO_AH:
tmp_ports = *(uint32_t *)(pkt->transport_header + 4);
break;
+#endif
default:
break;
}

View File

@ -0,0 +1,32 @@
diff -ru qemu-10.0.2/block/file-posix.c qemu-10.0.2-x86_64/block/file-posix.c
--- qemu-10.0.2/block/file-posix.c 2025-05-29 01:05:46.000000000 +0300
+++ qemu-10.0.2-x86_64/block/file-posix.c 2025-08-09 19:00:18.062695074 +0300
@@ -110,6 +110,10 @@
#include <sys/diskslice.h>
#endif
+#ifdef __banan_os__
+#include <sys/ioctl.h>
+#endif
+
/* OS X does not have O_DSYNC */
#ifndef O_DSYNC
#ifdef O_SYNC
Only in qemu-10.0.2-x86_64: build
Only in qemu-10.0.2-x86_64: .cache
diff -ru qemu-10.0.2/chardev/char-pty.c qemu-10.0.2-x86_64/chardev/char-pty.c
--- qemu-10.0.2/chardev/char-pty.c 2025-05-29 01:05:46.000000000 +0300
+++ qemu-10.0.2-x86_64/chardev/char-pty.c 2025-08-09 19:03:07.909515897 +0300
@@ -236,7 +236,11 @@
# include <termios.h>
#endif
-#ifdef __sun__
+#if defined(__banan_os__)
+# include <sys/ioctl.h>
+#endif
+
+#if defined(__sun__) || defined(__banan_os__)
#if !defined(HAVE_OPENPTY)
/* Once illumos has openpty(), this is going to be removed. */

View File

@ -19,7 +19,6 @@ setjmp:
xorl %eax, %eax
ret
.size setjmp, . - setjmp
// void longjmp(jmp_buf env, int val)
@ -39,5 +38,27 @@ longjmp:
movl 16(%edx), %edi
movl 20(%edx), %esi
jmp *%ecx
.size longjmp, . - longjmp
// int sigsetjmp(sigjmp_buf env, int savemask)
.global sigsetjmp
sigsetjmp:
movl 4(%esp), %edx
movl 8(%esp), %ecx
movl %ecx, 24(%edx)
testl %ecx, %ecx
jz setjmp
leal 24(%edx), %edx
xorl %ecx, %ecx
subl $12, %esp
movl %edx, 8(%esp)
movl %ecx, 4(%esp)
movl %ecx, 0(%esp)
call pthread_sigmask
addl $12, %esp
jmp setjmp
.size sigsetjmp, . - sigsetjmp

View File

@ -38,3 +38,21 @@ longjmp:
movq 56(%rdi), %r15
jmp *%rcx
.size longjmp, . - longjmp
// int sigsetjmp(sigjmp_buf env, int savemask)
.global sigsetjmp
sigsetjmp:
movq %rsi, 64(%rdi)
testq %rsi, %rsi
jz setjmp
subq $8, %rsp
movq %rdi, (%rsp)
leaq 72(%rsi), %rdx
xorq %rsi, %rsi
call pthread_sigmask
movq (%rsp), %rdi
addq $8, %rsp
jmp setjmp
.size sigsetjmp, . - sigsetjmp

View File

@ -1,5 +1,13 @@
#include <dlfcn.h>
extern "C" int __dladdr(const void*, Dl_info_t*) __attribute__((weak));
int dladdr(const void* __restrict addr, Dl_info_t* __restrict dlip)
{
if (&__dladdr == nullptr) [[unlikely]]
return 0;
return __dladdr(addr, dlip);
}
extern "C" int __dlclose(void*) __attribute__((weak));
int dlclose(void* handle)
{

View File

@ -26,7 +26,8 @@ typedef struct
typedef struct
{
pthread_mutexattr_t attr;
pthread_t locker;
uint32_t futex;
uint32_t waiters;
unsigned lock_depth;
} pthread_mutex_t;

View File

@ -15,6 +15,18 @@ __BEGIN_DECLS
#define RTLD_NEXT ((void*)-1)
#define RTLD_DEFAULT ((void*) 0)
struct Dl_info
{
const char* dli_fname; /* Pathname of mapped object file. */
void* dli_fbase; /* Base of mapped address range. */
const char* dli_sname; /* Sumbol name or null pointer. */
void* dli_saddr; /* Symbol address or null pointer. */
};
typedef struct Dl_info Dl_info_t; /* POSIX type */
typedef struct Dl_info Dl_info; /* Linux type */
int dladdr(const void* __restrict addr, Dl_info_t* __restrict dlip);
int dlclose(void* handle);
char* dlerror(void);
void* dlopen(const char* file, int mode);

View File

@ -79,7 +79,7 @@ struct uthread
#define PTHREAD_SPIN_INITIALIZER (pthread_spinlock_t)0
#define PTHREAD_COND_INITIALIZER (pthread_cond_t){ { CLOCK_REALTIME, 0 }, PTHREAD_SPIN_INITIALIZER, NULL }
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, 0 }, 0, 0 }
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, 0 }, 0, 0, 0 }
#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t){ { 0 }, 0, 0 }
#define _PTHREAD_ATFORK_PREPARE 0

View File

@ -132,8 +132,9 @@ struct sigevent
#define SA_SIGINFO 0x010
#define SA_NOCLDWAIT 0x020
#define SA_NODEFER 0x040
#define SS_ONSTACK 0x080
#define SS_DISABLE 0x100
#define SS_ONSTACK 1
#define SS_DISABLE 2
#define MINSIGSTKSZ 4096
#define SIGSTKSZ 4096

View File

@ -90,6 +90,9 @@ __BEGIN_DECLS
O(SYS_SIGACTION, sigaction) \
O(SYS_SIGPENDING, sigpending) \
O(SYS_SIGPROCMASK, sigprocmask) \
O(SYS_SIGSUSPEND, sigsuspend) \
O(SYS_SIGWAIT, sigwait) \
O(SYS_SIGALTSTACK, sigaltstack) \
O(SYS_SETITIMER, setitimer) \
O(SYS_POSIX_OPENPT, posix_openpt) \
O(SYS_PTSNAME, ptsname) \

View File

@ -146,7 +146,7 @@ __BEGIN_DECLS
#if !defined(__time_t_defined) && (defined(__need_all_types) || defined(__need_time_t))
#define __time_t_defined 1
typedef unsigned long long time_t;
typedef long long time_t;
#endif
#undef __need_time_t

View File

@ -17,7 +17,7 @@ __BEGIN_DECLS
#include <bits/types/locale_t.h>
typedef struct {} mbstate_t;
typedef int mbstate_t;
typedef int wctype_t;

View File

@ -736,34 +736,6 @@ int pthread_spin_unlock(pthread_spinlock_t* lock)
return 0;
}
template<typename T>
static int _pthread_timedlock(T* __restrict lock, const struct timespec* __restrict abstime, int (*trylock)(T*))
{
if (trylock(lock) == 0)
return 0;
constexpr auto has_timed_out =
[](const struct timespec* abstime) -> bool
{
struct timespec curtime;
clock_gettime(CLOCK_REALTIME, &curtime);
if (curtime.tv_sec < abstime->tv_sec)
return false;
if (curtime.tv_sec > abstime->tv_sec)
return true;
return curtime.tv_nsec >= abstime->tv_nsec;
};
while (!has_timed_out(abstime))
{
if (trylock(lock) == 0)
return 0;
sched_yield();
}
return ETIMEDOUT;
}
int pthread_mutexattr_destroy(pthread_mutexattr_t* attr)
{
(void)attr;
@ -835,7 +807,8 @@ int pthread_mutex_init(pthread_mutex_t* __restrict mutex, const pthread_mutexatt
attr = &default_attr;
*mutex = {
.attr = *attr,
.locker = 0,
.futex = 0,
.waiters = 0,
.lock_depth = 0,
};
return 0;
@ -843,55 +816,28 @@ int pthread_mutex_init(pthread_mutex_t* __restrict mutex, const pthread_mutexatt
int pthread_mutex_lock(pthread_mutex_t* mutex)
{
// NOTE: current yielding implementation supports shared
const auto tid = pthread_self();
switch (mutex->attr.type)
{
case PTHREAD_MUTEX_RECURSIVE:
if (mutex->locker != tid)
break;
mutex->lock_depth++;
return 0;
case PTHREAD_MUTEX_ERRORCHECK:
if (mutex->locker != tid)
break;
return EDEADLK;
}
pthread_t expected = 0;
while (!BAN::atomic_compare_exchange(mutex->locker, expected, tid, BAN::MemoryOrder::memory_order_acquire))
{
sched_yield();
expected = 0;
}
mutex->lock_depth = 1;
return 0;
return pthread_mutex_timedlock(mutex, nullptr);
}
int pthread_mutex_trylock(pthread_mutex_t* mutex)
{
// NOTE: current yielding implementation supports shared
const auto tid = pthread_self();
const uint32_t tid = pthread_self();
switch (mutex->attr.type)
{
case PTHREAD_MUTEX_RECURSIVE:
if (mutex->locker != tid)
if (mutex->futex != tid)
break;
mutex->lock_depth++;
return 0;
case PTHREAD_MUTEX_ERRORCHECK:
if (mutex->locker != tid)
if (mutex->futex != tid)
break;
return EDEADLK;
}
pthread_t expected = 0;
if (!BAN::atomic_compare_exchange(mutex->locker, expected, tid, BAN::MemoryOrder::memory_order_acquire))
uint32_t expected = 0;
if (!BAN::atomic_compare_exchange(mutex->futex, expected, tid, BAN::MemoryOrder::memory_order_acquire))
return EBUSY;
mutex->lock_depth = 1;
@ -900,18 +846,42 @@ int pthread_mutex_trylock(pthread_mutex_t* mutex)
int pthread_mutex_timedlock(pthread_mutex_t* __restrict mutex, const struct timespec* __restrict abstime)
{
return _pthread_timedlock(mutex, abstime, &pthread_mutex_trylock);
// recursive/errorcheck handled in trylock to remove code duplication
if (const int ret = pthread_mutex_trylock(mutex); ret != EBUSY)
return ret;
const uint32_t tid = pthread_self();
uint32_t expected = 0;
while (!BAN::atomic_compare_exchange(mutex->futex, expected, tid, BAN::memory_order_acquire))
{
const int op = FUTEX_WAIT | (mutex->attr.shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME;
BAN::atomic_add_fetch(mutex->waiters, 1);
const auto ret = futex(op, &mutex->futex, expected, abstime);
BAN::atomic_sub_fetch(mutex->waiters, 1);
if (ret == -1 && errno == ETIMEDOUT)
return ETIMEDOUT;
expected = 0;
}
mutex->lock_depth = 1;
return 0;
}
int pthread_mutex_unlock(pthread_mutex_t* mutex)
{
// NOTE: current yielding implementation supports shared
ASSERT(mutex->locker == pthread_self());
ASSERT(mutex->futex == static_cast<uint32_t>(pthread_self()));
mutex->lock_depth--;
if (mutex->lock_depth == 0)
BAN::atomic_store(mutex->locker, 0, BAN::MemoryOrder::memory_order_release);
{
BAN::atomic_store(mutex->futex, 0, BAN::memory_order_release);
if (BAN::atomic_load(mutex->waiters))
futex(FUTEX_WAKE, &mutex->futex, 1, nullptr);
}
return 0;
}
@ -971,6 +941,36 @@ int pthread_rwlock_init(pthread_rwlock_t* __restrict rwlock, const pthread_rwloc
return 0;
}
// TODO: rewrite rwlock with futexes
template<typename T>
static int pthread_rwlock_timedlock(T* __restrict lock, const struct timespec* __restrict abstime, int (*trylock)(T*))
{
if (trylock(lock) == 0)
return 0;
constexpr auto has_timed_out =
[](const struct timespec* abstime) -> bool
{
struct timespec curtime;
clock_gettime(CLOCK_REALTIME, &curtime);
if (curtime.tv_sec < abstime->tv_sec)
return false;
if (curtime.tv_sec > abstime->tv_sec)
return true;
return curtime.tv_nsec >= abstime->tv_nsec;
};
while (!has_timed_out(abstime))
{
if (trylock(lock) == 0)
return 0;
sched_yield();
}
return ETIMEDOUT;
}
int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock)
{
unsigned expected = BAN::atomic_load(rwlock->lockers);
@ -995,7 +995,7 @@ int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock)
int pthread_rwlock_timedrdlock(pthread_rwlock_t* __restrict rwlock, const struct timespec* __restrict abstime)
{
return _pthread_timedlock(rwlock, abstime, &pthread_rwlock_tryrdlock);
return pthread_rwlock_timedlock(rwlock, abstime, &pthread_rwlock_tryrdlock);
}
int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock)
@ -1021,7 +1021,7 @@ int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock)
int pthread_rwlock_timedwrlock(pthread_rwlock_t* __restrict rwlock, const struct timespec* __restrict abstime)
{
return _pthread_timedlock(rwlock, abstime, &pthread_rwlock_trywrlock);
return pthread_rwlock_timedlock(rwlock, abstime, &pthread_rwlock_trywrlock);
}
int pthread_rwlock_unlock(pthread_rwlock_t* rwlock)

View File

@ -7,13 +7,5 @@ void siglongjmp(sigjmp_buf env, int val)
{
if (env[_JMP_BUF_REGS])
pthread_sigmask(SIG_SETMASK, reinterpret_cast<sigset_t*>(&env[_JMP_BUF_REGS + 1]), nullptr);
return longjmp(env, val);
}
int sigsetjmp(sigjmp_buf env, int savemask)
{
env[_JMP_BUF_REGS] = savemask;
if (savemask)
pthread_sigmask(0, nullptr, reinterpret_cast<sigset_t*>(&env[_JMP_BUF_REGS + 1]));
return setjmp(env);
longjmp(env, val);
}

View File

@ -164,3 +164,22 @@ int sigrelse(int sig)
(void)sigaddset(&set, sig);
return sigprocmask(SIG_UNBLOCK, &set, nullptr);
}
int sigsuspend(const sigset_t* sigmask)
{
return syscall(SYS_SIGSUSPEND, sigmask);
}
int sigwait(const sigset_t* __restrict set, int* __restrict sig)
{
if (syscall(SYS_SIGWAIT, set, sig) == -1)
return errno;
return 0;
}
int sigaltstack(const stack_t* __restrict ss, stack_t* __restrict oss)
{
if (syscall(SYS_SIGALTSTACK, ss, oss) == -1)
return errno;
return 0;
}

View File

@ -606,6 +606,7 @@ int mbtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n)
return wch ? length : 0;
}
ASSERT_NOT_REACHED();
}
@ -645,6 +646,31 @@ size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n)
return written;
}
int wctomb(char* s, wchar_t wchar)
{
// no state-dependent encodings
if (s == nullptr)
return 0;
switch (__getlocale(LC_CTYPE))
{
case locale_t::LOCALE_INVALID:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
*s = wchar;
return wchar ? 1 : 0;
case locale_t::LOCALE_UTF8:
char buffer[5];
if (!BAN::UTF8::from_codepoints(&wchar, 1, buffer))
return -1;
const size_t length = strlen(buffer);
memcpy(s, buffer, length);
return length;
}
ASSERT_NOT_REACHED();
}
size_t wcstombs(char* __restrict s, const wchar_t* __restrict pwcs, size_t n)
{
size_t written = 0;

View File

@ -1,3 +1,4 @@
#include <BAN/Assert.h>
#include <BAN/Debug.h>
#include <BAN/Math.h>
@ -167,15 +168,18 @@ time_t mktime(struct tm* tm)
struct tm* gmtime_r(const time_t* timer, struct tm* __restrict result)
{
// FIXME: allow negative times :)
ASSERT(*timer >= 0);
constexpr uint64_t month_days[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
time_t time = *timer;
unsigned long long time = *timer;
result->tm_sec = time % 60; time /= 60;
result->tm_min = time % 60; time /= 60;
result->tm_hour = time % 24; time /= 24;
time_t total_days = time;
unsigned long long total_days = time;
result->tm_wday = (total_days + 4) % 7;
result->tm_year = 1970;
while (total_days >= 365U + is_leap_year(result->tm_year))

View File

@ -335,6 +335,10 @@ namespace LibGUI
if (m_window_shown_event_callback)
m_window_shown_event_callback(TRY_OR_BREAK(EventPacket::WindowShownEvent::deserialize(packet_data.span())).event);
break;
case PacketType::WindowFocusEvent:
if (m_window_focus_event_callback)
m_window_focus_event_callback(TRY_OR_BREAK(EventPacket::WindowFocusEvent::deserialize(packet_data.span())).event);
break;
case PacketType::KeyEvent:
if (m_key_event_callback)
m_key_event_callback(TRY_OR_BREAK(EventPacket::KeyEvent::deserialize(packet_data.span())).event);

View File

@ -217,6 +217,7 @@ namespace LibGUI
CloseWindowEvent,
ResizeWindowEvent,
WindowShownEvent,
WindowFocusEvent,
KeyEvent,
MouseButtonEvent,
MouseMoveEvent,
@ -333,6 +334,14 @@ namespace LibGUI
event_t, event
);
DEFINE_PACKET_EXTRA(
WindowFocusEvent,
struct event_t {
bool focused;
},
event_t, event
);
DEFINE_PACKET_EXTRA(
KeyEvent,
using event_t = LibInput::KeyEvent,

View File

@ -76,6 +76,7 @@ namespace LibGUI
void set_mouse_move_event_callback(BAN::Function<void(EventPacket::MouseMoveEvent::event_t)> callback) { m_mouse_move_event_callback = callback; }
void set_mouse_scroll_event_callback(BAN::Function<void(EventPacket::MouseScrollEvent::event_t)> callback) { m_mouse_scroll_event_callback = callback; }
void set_window_shown_event_callback(BAN::Function<void(EventPacket::WindowShownEvent::event_t)> callback) { m_window_shown_event_callback = callback; }
void set_window_focus_event_callback(BAN::Function<void(EventPacket::WindowFocusEvent::event_t)> callback) { m_window_focus_event_callback = callback; }
int server_fd() const { return m_server_fd; }
@ -108,6 +109,7 @@ namespace LibGUI
BAN::Function<void()> m_close_window_event_callback;
BAN::Function<void()> m_resize_window_event_callback;
BAN::Function<void(EventPacket::WindowShownEvent::event_t)> m_window_shown_event_callback;
BAN::Function<void(EventPacket::WindowFocusEvent::event_t)> m_window_focus_event_callback;
BAN::Function<void(EventPacket::KeyEvent::event_t)> m_key_event_callback;
BAN::Function<void(EventPacket::MouseButtonEvent::event_t)> m_mouse_button_event_callback;
BAN::Function<void(EventPacket::MouseMoveEvent::event_t)> m_mouse_move_event_callback;

View File

@ -58,7 +58,7 @@ namespace LibInput
"å", "ä", "ö",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, "\x7F", nullptr, nullptr, nullptr, nullptr, "\n", " ",
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, "\x7F", nullptr, nullptr, nullptr, nullptr, "\r", " ",
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
"(", ")", "[", "]", "{", "}",
"=", "?", "+", "\\", "´", "`", "¨", "¸", "\b", "@", "£", "$", "",
@ -77,7 +77,7 @@ namespace LibInput
"Å", "Ä", "Ö",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, "\x7F", nullptr, nullptr, nullptr, nullptr, "\n", " ",
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, "\x7F", nullptr, nullptr, nullptr, nullptr, "\r", " ",
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
"(", ")", "[", "]", "{", "}",
"=", "?", "+", "\\", "´", "`", "¨", "¸", "\b", "@", "£", "$", "",
@ -96,7 +96,7 @@ namespace LibInput
"Å", "Ä", "Ö",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, "\x7F", nullptr, nullptr, nullptr, nullptr, "\n", " ",
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, "\x7F", nullptr, nullptr, nullptr, nullptr, "\r", " ",
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
"(", ")", "[", "]", "{", "}",
"=", "?", "+", "\\", "´", "`", "¨", "¸", "\b", "@", "£", "$", "",

View File

@ -22,15 +22,15 @@ namespace LibInput
consteval uint8_t keycode_normal(uint8_t row, uint8_t col)
{
BANAN_CONSTEVAL_STATIC_ASSERT(row <= 0b111 - 1);
BANAN_CONSTEVAL_STATIC_ASSERT(col < 0b11111 - 8);
BANAN_CONSTEVAL_STATIC_ASSERT(col <= 0b11111 - 8);
return ((row + 1) << 5) | col;
}
consteval uint8_t keycode_numpad(uint8_t row, uint8_t col)
{
BANAN_CONSTEVAL_STATIC_ASSERT(row <= 0b111 - 1);
BANAN_CONSTEVAL_STATIC_ASSERT(col <= 8);
return ((row + 1) << 5) | (col + 0b11111 - 8);
BANAN_CONSTEVAL_STATIC_ASSERT(col < 8);
return ((row + 1) << 5) | (col + 0b11111 - 8 + 1);
}
enum class Key

View File

@ -116,11 +116,14 @@ uint64_t AudioServer::update()
if (!anyone_playing)
return 60'000;
// FIXME: this works but if any client stops producing audio samples
// the whole audio server halts
const uint32_t samples_per_10ms = m_sample_rate / 100;
if (max_sample_frames_to_queue < samples_per_10ms)
return 1;
const uint32_t sample_frames_per_10ms = m_sample_rate / 100;
if (max_sample_frames_to_queue < sample_frames_per_10ms)
{
const uint32_t sample_frames_sent = m_samples_sent / m_channels;
if (sample_frames_sent >= sample_frames_per_10ms)
return 1;
max_sample_frames_to_queue = sample_frames_per_10ms;
}
for (auto& [_, buffer] : m_audio_buffers)
{
@ -135,7 +138,7 @@ uint64_t AudioServer::update()
continue;
const size_t sample_frames_to_queue = BAN::Math::min<size_t>(max_sample_frames_to_queue, buffer_sample_frames_available);
if (sample_frames_to_queue < samples_per_10ms)
if (sample_frames_to_queue < sample_frames_per_10ms)
continue;
while (m_samples.size() < queued_samples_end + sample_frames_to_queue * m_channels)

View File

@ -190,6 +190,19 @@ struct LoadedElf
bool is_relocating;
char path[PATH_MAX];
struct LoadedPHDR
{
uintptr_t base;
size_t size;
};
LoadedPHDR loaded_phdrs[16];
size_t loaded_phdr_count;
size_t real_symtab_size;
size_t real_symtab_entsize;
const uint8_t* real_symtab_addr;
const uint8_t* real_strtab_addr;
};
static LoadedElf s_loaded_files[128];
@ -433,6 +446,7 @@ extern "C" int __dlclose(void* handle);
extern "C" char* __dlerror(void);
extern "C" void* __dlopen(const char* file, int mode);
extern "C" void* __dlsym(void* __restrict handle, const char* __restrict name);
extern "C" int __dladdr(const void* addr, Dl_info_t* dlip);
template<typename RelocT> requires BAN::is_same_v<RelocT, ElfNativeRelocation> || BAN::is_same_v<RelocT, ElfNativeRelocationA>
static uintptr_t handle_relocation(const LoadedElf& elf, const RelocT& reloc, bool resolve_symbols)
@ -458,6 +472,7 @@ static uintptr_t handle_relocation(const LoadedElf& elf, const RelocT& reloc, bo
CHECK_SYM(__dlerror);
CHECK_SYM(__dlopen);
CHECK_SYM(__dlsym);
CHECK_SYM(__dladdr);
#undef CHECK_SYM
else if (symbol.st_shndx && ELF_ST_BIND(symbol.st_info) != STB_WEAK)
symbol_address = elf.base + symbol.st_value;
@ -947,6 +962,64 @@ static void load_program_header(const ElfNativeProgramHeader& program_header, in
}
}
static bool read_section_header(const LoadedElf& elf, size_t index, ElfNativeSectionHeader& header)
{
if (index >= elf.file_header.e_shnum)
return false;
const auto& file_header = elf.file_header;
if (syscall(SYS_PREAD, elf.fd, &header, sizeof(header), file_header.e_shoff + index * file_header.e_shentsize) != sizeof(header))
return false;
return true;
}
static const uint8_t* mmap_section_header_data(const LoadedElf& elf, const ElfNativeSectionHeader& header)
{
const size_t offset_in_page = header.sh_offset % PAGE_SIZE;
const sys_mmap_t mmap_args {
.addr = nullptr,
.len = header.sh_size + offset_in_page,
.prot = PROT_READ,
.flags = MAP_SHARED,
.fildes = elf.fd,
.off = static_cast<off_t>(header.sh_offset - offset_in_page),
};
const uint8_t* mmap_ret = reinterpret_cast<const uint8_t*>(syscall(SYS_MMAP, &mmap_args));
if (mmap_ret == MAP_FAILED)
return nullptr;
return mmap_ret + offset_in_page;
}
static bool load_symbol_table(LoadedElf& elf)
{
if (elf.file_header.e_shentsize < sizeof(ElfNativeSectionHeader))
return false;
for (size_t i = 0; i < elf.file_header.e_shnum; i++)
{
ElfNativeSectionHeader symtab_header;
if (!read_section_header(elf, i, symtab_header))
return false;
if (symtab_header.sh_type != SHT_SYMTAB)
continue;
ElfNativeSectionHeader strtab_header;
if (!read_section_header(elf, symtab_header.sh_link, strtab_header))
return false;
elf.real_symtab_entsize = symtab_header.sh_entsize;
elf.real_symtab_size = symtab_header.sh_size;
elf.real_symtab_addr = mmap_section_header_data(elf, symtab_header);
elf.real_strtab_addr = mmap_section_header_data(elf, strtab_header);
return true;
}
return false;
}
static LoadedElf& load_elf(const char* path, int fd)
{
for (size_t i = 0; i < s_loaded_file_count; i++)
@ -1021,8 +1094,13 @@ static LoadedElf& load_elf(const char* path, int fd)
break;
}
ElfNativeProgramHeader tls_header {};
tls_header.p_type = PT_NULL;
auto& elf = s_loaded_files[s_loaded_file_count++];
elf.tls_header.p_type = PT_NULL;
elf.base = base;
elf.fd = fd;
elf.dynamics = nullptr;
memcpy(&elf.file_header, &file_header, sizeof(file_header));
strcpy(elf.path, path);
for (size_t i = 0; i < file_header.e_phnum; i++)
{
@ -1043,10 +1121,20 @@ static LoadedElf& load_elf(const char* path, int fd)
case PT_GNU_RELRO:
break;
case PT_TLS:
tls_header = program_header;
elf.tls_header = program_header;
break;
case PT_LOAD:
if (elf.loaded_phdr_count >= sizeof(elf.loaded_phdrs) / sizeof(*elf.loaded_phdrs))
{
print(STDERR_FILENO, "file '");
print(STDERR_FILENO, elf.path);
print_error_and_exit("' has too many PT_LOAD headers", 0);
}
program_header.p_vaddr += base;
elf.loaded_phdrs[elf.loaded_phdr_count++] = {
.base = program_header.p_vaddr,
.size = program_header.p_memsz,
};
load_program_header(program_header, fd, needs_writable);
break;
default:
@ -1056,13 +1144,6 @@ static LoadedElf& load_elf(const char* path, int fd)
}
}
auto& elf = s_loaded_files[s_loaded_file_count++];
elf.tls_header = tls_header;
elf.base = base;
elf.fd = fd;
elf.dynamics = nullptr;
memcpy(&elf.file_header, &file_header, sizeof(file_header));
strcpy(elf.path, path);
if (has_dynamic_pheader)
{
@ -1084,6 +1165,8 @@ static LoadedElf& load_elf(const char* path, int fd)
handle_dynamic(elf);
}
load_symbol_table(elf);
return elf;
}
@ -1419,6 +1502,88 @@ void* __dlsym(void* __restrict handle, const char* __restrict name)
return nullptr;
}
static bool elf_contains_address(const LoadedElf& elf, const void* address)
{
const uintptr_t addr_uptr = reinterpret_cast<uintptr_t>(address);
for (size_t i = 0; i < elf.loaded_phdr_count; i++)
{
const auto& phdr = elf.loaded_phdrs[i];
if (phdr.base <= addr_uptr && addr_uptr < phdr.base + phdr.size)
return true;
}
return false;
}
struct FindSymbolResult
{
const char* name;
void* addr;
};
static FindSymbolResult find_symbol_containing(const LoadedElf& elf, const void* address)
{
const uintptr_t addr_uptr = reinterpret_cast<uintptr_t>(address);
const size_t symbol_count = reinterpret_cast<const uint32_t*>(elf.hash)[1];
for (size_t i = 1; i < symbol_count; i++)
{
const auto& symbol = *reinterpret_cast<const ElfNativeSymbol*>(elf.symtab + i * elf.syment);
const uintptr_t symbol_base = elf.base + symbol.st_value;
if (!(symbol_base <= addr_uptr && addr_uptr < symbol_base + symbol.st_size))
continue;
return {
.name = reinterpret_cast<const char*>(elf.strtab + symbol.st_name),
.addr = reinterpret_cast<void*>(symbol_base),
};
}
if (!elf.real_symtab_addr || !elf.real_strtab_addr)
return {};
for (size_t i = 1; i < elf.real_symtab_size / elf.real_symtab_entsize; i++)
{
const auto& symbol = *reinterpret_cast<const ElfNativeSymbol*>(elf.real_symtab_addr + i * elf.real_symtab_entsize);
const uintptr_t symbol_base = elf.base + symbol.st_value;
if (!(symbol_base <= addr_uptr && addr_uptr < symbol_base + symbol.st_size))
continue;
return {
.name = reinterpret_cast<const char*>(elf.real_strtab_addr + symbol.st_name),
.addr = reinterpret_cast<void*>(symbol_base),
};
}
return {};
}
int __dladdr(const void* addr, Dl_info_t* dlip)
{
for (size_t i = 0; i < s_loaded_file_count; i++)
{
const auto& elf = s_loaded_files[i];
if (!elf_contains_address(elf, addr))
continue;
dlip->dli_fname = elf.path;
dlip->dli_fbase = reinterpret_cast<void*>(elf.base);
if (const auto symbol = find_symbol_containing(elf, addr); symbol.addr && symbol.name)
{
dlip->dli_sname = symbol.name;
dlip->dli_saddr = symbol.addr;
}
else
{
dlip->dli_sname = nullptr;
dlip->dli_saddr = nullptr;
}
return 1;
}
s_dlerror_string = "address is not contained in any file";
return 0;
}
static LibELF::AuxiliaryVector* find_auxv(char** envp)
{
if (envp == nullptr)

View File

@ -181,13 +181,6 @@ void Terminal::run()
perror("ioctl");
return;
}
const pid_t fgpgrp = tcgetpgrp(m_shell_info.pts_master);
if (fgpgrp == -1)
{
perror("tcgetpgrp");
return;
}
});
const int max_fd = BAN::Math::max(m_shell_info.pts_master, m_window->server_fd());
@ -676,6 +669,14 @@ Rectangle Terminal::putcodepoint(uint32_t codepoint)
auto& texture = m_window->texture();
switch (codepoint)
{
case 0x00: // null
case 0x01: // start of heading
case 0x02: // start of text
case 0x1C: // file separator
case 0x1D: // group separator
case 0x1E: // record separator
case 0x1F: // unit separator
break;
case '\a':
// TODO: bell
break;

View File

@ -90,7 +90,7 @@ void WindowServer::on_window_create(int fd, const LibGUI::WindowPacket::WindowCr
window_popper.disable();
if (packet.attributes.focusable)
if (packet.attributes.shown && packet.attributes.focusable)
set_focused_window(window);
else if (m_client_windows.size() > 1)
BAN::swap(m_client_windows[m_client_windows.size() - 1], m_client_windows[m_client_windows.size() - 2]);
@ -197,6 +197,9 @@ void WindowServer::on_window_set_attributes(int fd, const LibGUI::WindowPacket::
};
if (auto ret = event_packet.send_serialized(target_window->client_fd()); ret.is_error())
dwarnln("could not send window shown event: {}", ret.error());
if (packet.attributes.focusable && packet.attributes.shown)
set_focused_window(target_window);
}
void WindowServer::on_window_set_mouse_relative(int fd, const LibGUI::WindowPacket::WindowSetMouseRelative& packet)
@ -512,7 +515,9 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
}
BAN::RefPtr<Window> target_window;
if (!event.pressed)
if (m_state == State::Fullscreen)
target_window = m_focused_window;
if (!event.pressed && !target_window)
target_window = m_mouse_button_windows[button_idx];
for (size_t i = m_client_windows.size(); i > 0 && !target_window; i--)
if (m_client_windows[i - 1]->full_area().contains(m_cursor) && m_client_windows[i - 1]->get_attributes().shown)
@ -556,7 +561,7 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
if (event.button == LibInput::MouseButton::Left && !event.pressed && target_window->close_button_area().contains(m_cursor))
{
LibGUI::EventPacket::CloseWindowEvent packet;
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
if (auto ret = packet.send_serialized(target_window->client_fd()); ret.is_error())
dwarnln("could not send close window event: {}", ret.error());
break;
}
@ -568,9 +573,9 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
LibGUI::EventPacket::MouseButtonEvent packet;
packet.event.button = event.button;
packet.event.pressed = event.pressed;
packet.event.x = m_cursor.x - m_focused_window->client_x();
packet.event.y = m_cursor.y - m_focused_window->client_y();
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
packet.event.x = m_cursor.x - target_window->client_x();
packet.event.y = m_cursor.y - target_window->client_y();
if (auto ret = packet.send_serialized(target_window->client_fd()); ret.is_error())
{
dwarnln("could not send mouse button event: {}", ret.error());
return;
@ -779,6 +784,17 @@ void WindowServer::set_focused_window(BAN::RefPtr<Window> window)
invalidate(cursor_area());
}
if (m_focused_window)
{
LibGUI::EventPacket::WindowFocusEvent packet;
packet.event.focused = false;
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
{
dwarnln("could not send window focus event: {}", ret.error());
return;
}
}
for (size_t i = m_client_windows.size(); i > 0; i--)
{
if (m_client_windows[i - 1] == window)
@ -790,6 +806,17 @@ void WindowServer::set_focused_window(BAN::RefPtr<Window> window)
break;
}
}
if (m_focused_window)
{
LibGUI::EventPacket::WindowFocusEvent packet;
packet.event.focused = true;
if (auto ret = packet.send_serialized(m_focused_window->client_fd()); ret.is_error())
{
dwarnln("could not send window focus event: {}", ret.error());
return;
}
}
}
static uint32_t alpha_blend(uint32_t color_a, uint32_t color_b)
@ -1410,6 +1437,10 @@ void WindowServer::remove_client_fd(int fd)
invalidate(m_framebuffer.area());
}
for (auto& window : m_mouse_button_windows)
if (window && window->client_fd() == fd)
window.clear();
for (size_t i = 0; i < m_client_windows.size(); i++)
{
auto window = m_client_windows[i];