Compare commits

...
47 Commits
Author SHA1 Message Date
Bananymous 328771ae29 Kernel: Fix AC97 issues
Set last entry bit on the last entry :D

Verify that allocated DMA buffer fits in a 32 bit integer
2026-07-20 11:30:06 +03:00
Bananymous 0b53fba991 Kernel: Fix PCI PIN interrupt allocation and handling
We now use the correct PIN interrupt from the interrupt line field
instead of writing to it, this had no effect :D

PIN interrupts are now mapped as shared and level triggered, this
properly allows PIN interrupt sharing with multiple devices
2026-07-20 10:45:32 +03:00
Bananymous 0d390e2246 Kernel: Send EOI after handling the interrupt
There is no need to send it prior to handling. This required us to not
yield from HPET/PIT irq so that the EOI actually gets sent
2026-07-20 10:43:50 +03:00
Bananymous a3b7a758eb Kernel: Allow allocating shared interrupts and setting trigger mode 2026-07-20 10:28:18 +03:00
Bananymous d46d7a5123 Kernel: Cleanup entering acpi mode
There is no need to pass the current mode as an argument as ACPI has
access to that info either way.

Only route INTx objects when using ACPI, they won't be used otherwise
2026-07-20 09:02:18 +03:00
Bananymous b611c3fe48 LibC: Support in-place realloc for mmap backed allocations
When shrinking a mmap based allocation, we can just unmap the trailing
pages that will no longer be needed. When extending an allocation we try
to MMAP_FIXED_NOREPLACE the need extra data to avoid memcpy between old
and new allocation. I'm not sure if the extension logic is really worth
it but it is just 15 lines of code to avoid possibly very large memcpys.
2026-07-20 06:58:30 +03:00
Bananymous 8c6e402ee8 LibC: page align mmap backed malloc sizes
This will make reallocations cleaner
2026-07-20 06:58:30 +03:00
Bananymous bd5be982e9 LibC: Don't memset 0 mmap'd callocs
There is no reason to page everything in and the kernel already
guarantees that the memory is zeroed in mmap
2026-07-20 06:58:30 +03:00
Bananymous 33f941f2fd LibC: Unmap unused pages in aligned mallocs 2026-07-20 06:58:30 +03:00
Bananymous 8368dec30b LibC: Fix posix_memalign return value
I was returning -1 with errno instead of the error code :P
2026-07-20 06:58:30 +03:00
Bananymous 7f25350c62 LibC: Fix malloc mmap byte tracking
I was incrementing instead of decrementing when freeing mmap allocs
2026-07-20 06:58:30 +03:00
Bananymous 64523b6c70 LibC: Fix futex return value handling 2026-07-20 06:58:30 +03:00
Bananymous a9cf0134b7 Kernel: Don't block thread if the wake time has already passed 2026-07-20 06:58:30 +03:00
Bananymous 2e8239fefa Kernel: Fix thread block timeout
I was comparint ms against ns making timeouts practically never wake up
:)
2026-07-20 06:58:30 +03:00
Bananymous f2bf406db7 ports: Add ccleste port 2026-07-20 06:58:30 +03:00
Bananymous 63a8f40e67 ports/quake2: Clenaup build script and patches 2026-07-20 06:58:30 +03:00
Bananymous 2ddee7016e Kernel: Fix another scheduler bug :^) 2026-07-20 06:58:30 +03:00
Bananymous bc622c8b51 LibC: Fix pthread default guard size and name 2026-07-20 06:58:30 +03:00
Bananymous 6ebd3a8aca Kernel: Rewrite the AHCI driver
There was a lot of stuff wrong with this driver and it was only getting
speeds of ~2.5 MB/s. Now 4K blocks get ~17 MB/s which is not good but
definitely better. I'm pretty sure the issue is qemu's emulation as 85%
of time is spent between sending the command and it to complete.
Large blocks are now supported too, qemu with block size 1M gets around
600 MB/s read speeds.
2026-07-20 06:58:30 +03:00
Bananymous 96e5779182 Kernel: Fix out of bounds reads on storage devices 2026-07-20 04:07:23 +03:00
Bananymous 02f05436fc Kernel: Fix zero sized reads from a partition 2026-07-20 04:07:23 +03:00
Bananymous 51251e492e Kernel: Fix fallback PS/2 interrupt numbers
I haven't used the fallbacks in so long that I didn't realize they were
wrong :D
2026-07-20 04:07:23 +03:00
Bananymous 20e36125c8 Kernel: Cleanup very old AHCI code 2026-07-20 04:07:23 +03:00
Bananymous 19c228362b Kernel: Make ext2 block buffers page aligned 2026-07-20 04:07:23 +03:00
Bananymous cf9a495f1d ports: Add ClassiCube port 2026-07-20 04:07:23 +03:00
Bananymous 5329ec5912 Kernel: Rework spinlock usage when blocking the current thread
The old SpinLockAsMutex was pretty confusing first of all. It also was
causing the issue thats been around for maybe a year now which is the
only consistently happening kernel panic. I've been pretty confused
about this and finally figured out what was causing this.

The main issue was that we were accidentally enabling interrupts when
blocking a thread that passed SpinLockAsMutex from normally interrupt
enabled context. This led to receiving IPI for thread unblock while
we were actively blocking the thread. I'm very suprized this had't
caused any more serious issues than occasional kernel panics :^)
2026-07-20 04:07:23 +03:00
Bananymous edc95e1c09 Kernel: Disable SMP message handling while blocking a thread
There were some race conditions on a thread getting unblocked before
being moved to the block queue
2026-07-20 04:07:23 +03:00
Bananymous 46e2d665e9 LibC: Make pthread_once block with a futex instead of yielding 2026-07-20 04:07:23 +03:00
Bananymous 0242a4f968 DynamicLoader: Fix master and initial TLS setup 2026-07-20 04:07:23 +03:00
Bananymous 390a7674b1 LibC: Fix uthread deallocation
Update dtv[0] to the max loadad module when loading dynamic modules

Free uthread if stack allocation or mprotect fails on pthread_create

Don't unmap the currently used stack when detached thread exits
2026-07-20 04:07:23 +03:00
Bananymous f96f2b4cac ports: Split dejavu fonts to their own port 2026-07-20 04:07:23 +03:00
Bananymous 51b9dcebbc Kernel: Support FIONBIO ioctl 2026-07-20 04:07:23 +03:00
Bananymous 583c2437b4 LibC: Don't munmap nullptr with 0 size in malloc 2026-07-20 04:07:23 +03:00
Bananymous efb25e5666 BAN/LibC: Move ldexp, scalbn to libc
They are now implemented with float decompostion to modify the exponent
bits directly
2026-07-20 04:07:23 +03:00
Bananymous f0e95ffe48 LibC: Make qsort_swap static
There is no need to export this
2026-07-20 04:07:23 +03:00
Bananymous 511ab7e99c LibC: Define locale_t as an poiter
A lot of ports seem to depend on this casting nullptr into locale_t
2026-07-20 04:07:23 +03:00
Bananymous 4df58c5155 Kernel: Check for overflow in seek syscall 2026-07-20 04:07:23 +03:00
Bananymous f6e27e5f05 toolchain: Update gcc 15.2.0->15.3.0
There was an ICE bug in gcc 15.2.x when compiling webkitgtk
2026-07-20 04:07:23 +03:00
Bananymous 87006e277f LibC: Define winsize in both termios.h and sys/ioctl.h 2026-07-20 04:07:23 +03:00
Bananymous 2c340c5532 BAN: Implement more numerically stable hypot 2026-07-20 04:07:23 +03:00
Bananymous f6b91578ae LibC: Enable backtrace dumping by default
I'm not sure why I had turned this off
2026-07-20 04:07:23 +03:00
Bananymous 73a95bd725 ports/lynx: Update 2.9.2->2.9.3 and fix compilation 2026-07-20 04:07:23 +03:00
Bananymous 130c4f681c ports/ncurses: Enable widec support and disable test compilation
There is one test with buggy macros that does not compile and im not
feeling like making a patch for it now :^)
2026-07-20 04:07:23 +03:00
Bananymous e03a26cf01 LibC: Don't ASSERT in times
Return the current process CPU time as user time. We don't have a way to
get system/user time separation or CPU times of child processes
2026-07-20 04:07:23 +03:00
Bananymous 2a3eca5b36 LibC: Implement POSIX binary search trees
I used RB tree for this. The implementation is based on the code on
wikipedia about RB trees.
2026-07-20 04:07:23 +03:00
Bananymous 658e74b507 bootloader: Check that VESA mode is linear
I don't think there are any graphical non-linear framebuffers but good
to be sure
2026-07-20 04:07:23 +03:00
Bananymous 9bdf60bb88 bootloader: Fix stack corruption when pressing non ascii keys 2026-07-20 04:07:23 +03:00
89 changed files with 1844 additions and 928 deletions
+12 -31
View File
@@ -2,6 +2,7 @@
#include <BAN/Limits.h> #include <BAN/Limits.h>
#include <BAN/Numbers.h> #include <BAN/Numbers.h>
#include <BAN/Swap.h>
#include <BAN/Traits.h> #include <BAN/Traits.h>
#include <float.h> #include <float.h>
@@ -308,36 +309,6 @@ namespace BAN::Math
return exp2<T>(y * log2<T>(x)); return exp2<T>(y * log2<T>(x));
} }
template<floating_point T>
inline constexpr T scalbn(T x, int n)
{
asm("fscale" : "+t"(x) : "u"(static_cast<T>(n)));
return x;
}
template<floating_point T>
inline constexpr T ldexp(T x, int y)
{
const bool exp_sign = y < 0;
if (exp_sign)
y = -y;
T exp = (T)1.0;
T mult = (T)2.0;
while (y)
{
if (y & 1)
exp *= mult;
mult *= mult;
y >>= 1;
}
if (exp_sign)
exp = (T)1.0 / exp;
return x * exp;
}
template<floating_point T> template<floating_point T>
inline constexpr T sqrt(T x) inline constexpr T sqrt(T x)
{ {
@@ -470,7 +441,17 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
inline constexpr T hypot(T x, T y) inline constexpr T hypot(T x, T y)
{ {
return sqrt<T>(x * x + y * y); x = abs(x);
y = abs(y);
if (x < y)
swap(x, y);
if (y == (T)0.0)
return x;
const T r = y / x;
return x * sqrt<T>((T)1.0 + r * r);
} }
#ifdef BAN_MATH_POP_OPTIONS #ifdef BAN_MATH_POP_OPTIONS
+2 -2
View File
@@ -35,13 +35,13 @@ read_user_command_line:
cmpb $'\n', %al cmpb $'\n', %al
je .read_user_command_line_done je .read_user_command_line_done
pushw %ax movb %al, %bl
call isprint call isprint
testb %al, %al testb %al, %al
jz .read_user_command_line_loop jz .read_user_command_line_loop
popw %ax movb %bl, %al
# put byte to buffer # put byte to buffer
movb %al, (%di) movb %al, (%di)
+5 -3
View File
@@ -108,9 +108,11 @@ vesa_find_video_mode:
cmpb $0x4F, %al; jne .vesa_unsupported cmpb $0x4F, %al; jne .vesa_unsupported
cmpb $0x00, %ah; jne .vesa_error cmpb $0x00, %ah; jne .vesa_error
# check whether in graphics mode # check whether in graphics mode and linear framebuffer
testb $0x10, (vesa_mode_info_buffer + 0) movb (vesa_mode_info_buffer + 0), %al
jz .vesa_find_video_mode_next_mode andb $(0x80 | 0x10), %al
cmpb $(0x80 | 0x10), %al
jne .vesa_find_video_mode_next_mode
# compare mode's dimensions # compare mode's dimensions
movw -2(%ebp), %ax; cmpw %ax, (vesa_mode_info_buffer + 0x12) movw -2(%ebp), %ax; cmpw %ax, (vesa_mode_info_buffer + 0x12)
+1 -5
View File
@@ -23,11 +23,7 @@ namespace Kernel::ACPI
const SDTHeader* get_header(BAN::StringView signature, uint32_t index); const SDTHeader* get_header(BAN::StringView signature, uint32_t index);
// mode BAN::ErrorOr<void> enter_acpi_mode();
// 0: PIC
// 1: APIC
// 2: SAPIC
BAN::ErrorOr<void> enter_acpi_mode(uint8_t mode);
BAN::ErrorOr<void> initialize_acpi_devices(); BAN::ErrorOr<void> initialize_acpi_devices();
+5 -4
View File
@@ -12,10 +12,10 @@ namespace Kernel
{ {
public: public:
virtual void eoi(uint8_t) override; virtual void eoi(uint8_t) override;
virtual void enable_irq(uint8_t) override; virtual void enable_irq(uint8_t, bool level_triggered) override;
virtual bool is_in_service(uint8_t) override; virtual bool is_in_service(uint8_t) override;
virtual BAN::ErrorOr<void> reserve_irq(uint8_t irq) override; virtual BAN::ErrorOr<void> reserve_irq(uint8_t irq, bool shared) override;
virtual BAN::Optional<uint8_t> get_free_irq() override; virtual BAN::Optional<uint8_t> get_free_irq() override;
virtual void initialize_multiprocessor() override; virtual void initialize_multiprocessor() override;
@@ -23,7 +23,7 @@ namespace Kernel
virtual void broadcast_ipi() override; virtual void broadcast_ipi() override;
virtual void enable() override; virtual void enable() override;
BAN::ErrorOr<uint8_t> reserve_gsi(uint32_t gsi); BAN::ErrorOr<uint8_t> reserve_gsi(uint32_t gsi, bool shared = false);
void initialize_timer(); void initialize_timer();
void set_timer_dealine(uint64_t ns); void set_timer_dealine(uint64_t ns);
@@ -71,7 +71,8 @@ namespace Kernel
Kernel::vaddr_t m_local_apic_vaddr = 0; Kernel::vaddr_t m_local_apic_vaddr = 0;
BAN::Vector<IOAPIC> m_io_apics; BAN::Vector<IOAPIC> m_io_apics;
uint8_t m_irq_overrides[0x100] {}; uint8_t m_irq_overrides[0x100] {};
uint8_t m_reserved_gsis[m_irq_count / 8] {}; uint8_t m_used_gsis[m_irq_count / 8] {};
uint8_t m_excl_gsis[m_irq_count / 8] {};
uint64_t m_lapic_timer_frequency_hz { 0 }; uint64_t m_lapic_timer_frequency_hz { 0 };
}; };
+5 -4
View File
@@ -28,7 +28,7 @@ namespace Kernel
BAN_NON_COPYABLE(BlockBufferWrapper); BAN_NON_COPYABLE(BlockBufferWrapper);
public: public:
BlockBufferWrapper(BAN::Span<uint8_t> buffer, void (*callback)(void*, const uint8_t*), void* argument) BlockBufferWrapper(BAN::ByteSpan buffer, void (*callback)(void*, const uint8_t*), void* argument)
: m_buffer(buffer) : m_buffer(buffer)
, m_callback(callback) , m_callback(callback)
, m_argument(argument) , m_argument(argument)
@@ -60,13 +60,13 @@ namespace Kernel
const uint8_t* data() const { return m_buffer.data(); } const uint8_t* data() const { return m_buffer.data(); }
BAN::ByteSpan span() { return m_buffer; } BAN::ByteSpan span() { return m_buffer; }
BAN::ConstByteSpan span() const { return m_buffer.as_const(); } BAN::ConstByteSpan span() const { return m_buffer; }
uint8_t& operator[](size_t index) { return m_buffer[index]; } uint8_t& operator[](size_t index) { return m_buffer[index]; }
uint8_t operator[](size_t index) const { return m_buffer[index]; } uint8_t operator[](size_t index) const { return m_buffer[index]; }
private: private:
BAN::Span<uint8_t> m_buffer; BAN::ByteSpan m_buffer;
void (*m_callback)(void*, const uint8_t*); void (*m_callback)(void*, const uint8_t*);
void* m_argument; void* m_argument;
}; };
@@ -128,7 +128,7 @@ namespace Kernel
private: private:
struct BlockBuffer struct BlockBuffer
{ {
BAN::Vector<uint8_t> buffer; BAN::ByteSpan buffer;
bool used { false }; bool used { false };
}; };
@@ -144,6 +144,7 @@ namespace Kernel
Mutex m_buffer_mutex; Mutex m_buffer_mutex;
ThreadBlocker m_buffer_blocker; ThreadBlocker m_buffer_blocker;
BAN::UniqPtr<VirtualRange> m_buffer_data;
BAN::Array<BlockBuffer, max_threads * max_buffers_per_thread> m_buffers; BAN::Array<BlockBuffer, max_threads * max_buffers_per_thread> m_buffers;
BAN::Array<ThreadInfo, max_threads> m_thread_infos; BAN::Array<ThreadInfo, max_threads> m_thread_infos;
}; };
+2 -2
View File
@@ -14,7 +14,7 @@ namespace Kernel
virtual ~InterruptController() {} virtual ~InterruptController() {}
virtual void eoi(uint8_t) = 0; virtual void eoi(uint8_t) = 0;
virtual void enable_irq(uint8_t) = 0; virtual void enable_irq(uint8_t, bool level_triggered = false) = 0;
virtual bool is_in_service(uint8_t) = 0; virtual bool is_in_service(uint8_t) = 0;
static void initialize(bool force_pic); static void initialize(bool force_pic);
@@ -26,7 +26,7 @@ namespace Kernel
virtual void broadcast_ipi() = 0; virtual void broadcast_ipi() = 0;
virtual void enable() = 0; virtual void enable() = 0;
virtual BAN::ErrorOr<void> reserve_irq(uint8_t irq) = 0; virtual BAN::ErrorOr<void> reserve_irq(uint8_t irq, bool shared = false) = 0;
virtual BAN::Optional<uint8_t> get_free_irq() = 0; virtual BAN::Optional<uint8_t> get_free_irq() = 0;
bool is_using_apic() const { return m_using_apic; } bool is_using_apic() const { return m_using_apic; }
@@ -0,0 +1,41 @@
#pragma once
#include <kernel/Lock/SpinLock.h>
#include <kernel/Lock/Mutex.h>
namespace Kernel
{
// FIXME: These classes are HACKS to allow passing spinlock
// to unblock functions. Write a better API that either
// allows passing spinlocks or do something cleaner that
// whatever shit this is
template<typename Lock> requires requires (Lock& lock) { lock.lock(); lock.unlock(InterruptState::Disabled); lock.current_processor_has_lock(); }
class BlockableSpinLock : public BaseMutex
{
public:
BlockableSpinLock(Lock& lock)
: m_lock(lock)
{
ASSERT(m_lock.current_processor_has_lock());
}
void lock() override
{
m_lock.lock();
}
void unlock() override
{
m_lock.unlock(InterruptState::Disabled);
}
uint32_t lock_depth() const override { return m_lock.lock_depth(); }
bool is_locked_by_current_thread() const override { return m_lock.current_processor_has_lock(); }
private:
Lock& m_lock;
};
}
+9 -11
View File
@@ -13,12 +13,10 @@ namespace Kernel
{ {
public: public:
virtual void lock() = 0; virtual void lock() = 0;
virtual bool try_lock() = 0;
virtual void unlock() = 0; virtual void unlock() = 0;
virtual pid_t locker() const = 0;
virtual bool is_locked() const = 0;
virtual uint32_t lock_depth() const = 0; virtual uint32_t lock_depth() const = 0;
virtual bool is_locked_by_current_thread() const = 0;
}; };
class Mutex final : public BaseMutex class Mutex final : public BaseMutex
@@ -51,7 +49,7 @@ namespace Kernel
m_lock_depth++; m_lock_depth++;
} }
bool try_lock() override bool try_lock()
{ {
const auto tid = Thread::current_tid(); const auto tid = Thread::current_tid();
if (tid == m_locker) if (tid == m_locker)
@@ -82,10 +80,10 @@ namespace Kernel
} }
} }
pid_t locker() const override { return m_locker; } pid_t locker() const { return m_locker; }
bool is_locked() const override { return m_locker != -1; } bool is_locked() const { return m_locker != -1; }
uint32_t lock_depth() const override { return m_lock_depth; } uint32_t lock_depth() const override { return m_lock_depth; }
bool is_locked_by_current_thread() const { return m_locker == Thread::current_tid(); } bool is_locked_by_current_thread() const override { return m_locker == Thread::current_tid(); }
private: private:
BAN::Atomic<pid_t> m_locker { -1 }; BAN::Atomic<pid_t> m_locker { -1 };
@@ -126,7 +124,7 @@ namespace Kernel
m_lock_depth++; m_lock_depth++;
} }
bool try_lock() override bool try_lock()
{ {
const auto tid = Thread::current_tid(); const auto tid = Thread::current_tid();
@@ -164,10 +162,10 @@ namespace Kernel
} }
} }
pid_t locker() const override { return m_locker; } pid_t locker() const { return m_locker; }
bool is_locked() const override { return m_locker != -1; } bool is_locked() const { return m_locker != -1; }
uint32_t lock_depth() const override { return m_lock_depth; } uint32_t lock_depth() const override { return m_lock_depth; }
bool is_locked_by_current_thread() const { return m_locker == Thread::current_tid(); } bool is_locked_by_current_thread() const override { return m_locker == Thread::current_tid(); }
private: private:
BAN::Atomic<pid_t> m_locker { -1 }; BAN::Atomic<pid_t> m_locker { -1 };
+5 -5
View File
@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Lock/SpinLock.h> #include <kernel/Lock/SpinLock.h>
#include <kernel/Lock/SpinLockAsMutex.h>
namespace Kernel namespace Kernel
{ {
@@ -18,8 +18,8 @@ namespace Kernel
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
while (m_writers_waiting > 0 || m_writer != -1) while (m_writers_waiting > 0 || m_writer != -1)
{ {
SpinLockGuardAsMutex smutex(_); BlockableSpinLock block(m_lock);
m_thread_blocker.block_indefinite(&smutex); m_thread_blocker.block_indefinite(&block);
} }
m_readers_active++; m_readers_active++;
} }
@@ -44,8 +44,8 @@ namespace Kernel
m_writers_waiting++; m_writers_waiting++;
while (m_readers_active > 0 || m_writer != -1) while (m_readers_active > 0 || m_writer != -1)
{ {
SpinLockGuardAsMutex smutex(_); BlockableSpinLock block(m_lock);
m_thread_blocker.block_indefinite(&smutex); m_thread_blocker.block_indefinite(&block);
} }
m_writers_waiting--; m_writers_waiting--;
@@ -1,64 +0,0 @@
#pragma once
#include <kernel/Lock/SpinLock.h>
#include <kernel/Lock/Mutex.h>
namespace Kernel
{
// FIXME: These classes are HACKS to allow passing spinlock
// to unblock functions. Write a better API that either
// allows passing spinlocks or do something cleaner that
// whatever shit this is
template<typename Lock>
class SpinLockAsMutex : public BaseMutex
{
public:
SpinLockAsMutex(Lock& lock, InterruptState state)
: m_lock(lock)
, m_lock_depth(lock.lock_depth())
, m_state(state)
, m_locker(Thread::current_tid())
{
ASSERT(m_lock.current_processor_has_lock());
}
void lock() override
{
m_lock.lock();
m_lock_depth++;
}
bool try_lock() override
{
lock();
return true;
}
void unlock() override
{
m_lock.unlock(--m_lock_depth ? InterruptState::Disabled : m_state);
}
pid_t locker() const override { return is_locked() ? m_locker : -1; }
bool is_locked() const override { return m_lock_depth; }
uint32_t lock_depth() const override { return m_lock_depth; }
private:
Lock& m_lock;
uint32_t m_lock_depth { 0 };
InterruptState m_state;
const pid_t m_locker;
};
template<typename Lock>
class SpinLockGuardAsMutex : public SpinLockAsMutex<Lock>
{
public:
SpinLockGuardAsMutex(SpinLockGuard<Lock>& guard)
: SpinLockAsMutex<Lock>(guard.m_lock, guard.m_state)
{}
};
}
@@ -34,6 +34,7 @@ namespace Kernel
BAN::ErrorOr<int> dup2(int, int); BAN::ErrorOr<int> dup2(int, int);
BAN::ErrorOr<int> fcntl(int fd, int cmd, uintptr_t extra); BAN::ErrorOr<int> fcntl(int fd, int cmd, uintptr_t extra);
BAN::ErrorOr<long> ioctl(int fd, unsigned long request, void* arg);
BAN::ErrorOr<off_t> seek(int fd, off_t offset, int whence); BAN::ErrorOr<off_t> seek(int fd, off_t offset, int whence);
BAN::ErrorOr<off_t> tell(int) const; BAN::ErrorOr<off_t> tell(int) const;
+4 -3
View File
@@ -10,10 +10,10 @@ namespace Kernel
{ {
public: public:
virtual void eoi(uint8_t) override; virtual void eoi(uint8_t) override;
virtual void enable_irq(uint8_t) override; virtual void enable_irq(uint8_t, bool level_triggered) override;
virtual bool is_in_service(uint8_t) override; virtual bool is_in_service(uint8_t) override;
virtual BAN::ErrorOr<void> reserve_irq(uint8_t irq) override; virtual BAN::ErrorOr<void> reserve_irq(uint8_t irq, bool shared) override;
virtual BAN::Optional<uint8_t> get_free_irq() override; virtual BAN::Optional<uint8_t> get_free_irq() override;
virtual void initialize_multiprocessor() override; virtual void initialize_multiprocessor() override;
@@ -29,7 +29,8 @@ namespace Kernel
private: private:
SpinLock m_lock; SpinLock m_lock;
uint16_t m_reserved_irqs { 1u << 2 }; uint16_t m_used_irqs { 1u << 2 };
uint16_t m_excl_irqs { 1u << 2 };
friend class InterruptController; friend class InterruptController;
}; };
+10 -1
View File
@@ -104,10 +104,17 @@ namespace Kernel
static void pause() static void pause()
{ {
__builtin_ia32_pause(); __builtin_ia32_pause();
if (is_smp_enabled()) if (is_smp_enabled() && !smp_messages_disabled())
handle_smp_messages(); handle_smp_messages();
} }
static bool smp_messages_disabled() { return read_gs_sized<bool>(offsetof(Processor, m_smp_messages_disabled)); }
static void set_disable_smp_messages(bool disabled)
{
ASSERT(smp_messages_disabled() != disabled);
write_gs_sized<bool>(offsetof(Processor, m_smp_messages_disabled), disabled);
}
vaddr_t stack_top_vaddr() const { return m_stack_vaddr + s_stack_size; } vaddr_t stack_top_vaddr() const { return m_stack_vaddr + s_stack_size; }
paddr_t stack_top_paddr() const { return m_stack_paddr + s_stack_size; } paddr_t stack_top_paddr() const { return m_stack_paddr + s_stack_size; }
@@ -198,6 +205,8 @@ namespace Kernel
ProcessorID m_id { 0 }; ProcessorID m_id { 0 };
uint8_t m_index { 0 }; uint8_t m_index { 0 };
bool m_smp_messages_disabled { false };
vaddr_t m_thread_syscall_stack; vaddr_t m_thread_syscall_stack;
Thread* m_sse_thread { nullptr }; Thread* m_sse_thread { nullptr };
+3 -1
View File
@@ -58,7 +58,7 @@ namespace Kernel
BAN::ErrorOr<void> initialize(); BAN::ErrorOr<void> initialize();
void reschedule(YieldRegisters*); void reschedule(YieldRegisters*);
void reschedule_if_idle(); void reschedule_if_needed();
void on_timer_interrupt(); void on_timer_interrupt();
void on_yield(YieldRegisters*); void on_yield(YieldRegisters*);
@@ -118,6 +118,8 @@ namespace Kernel
bool m_should_calculate_max_load_threads { true }; bool m_should_calculate_max_load_threads { true };
bool m_has_pending_reschedule { false };
Thread* m_idle_thread { nullptr }; Thread* m_idle_thread { nullptr };
friend class ThreadBlocker; friend class ThreadBlocker;
@@ -22,6 +22,7 @@ namespace Kernel
virtual void handle_irq() override; virtual void handle_irq() override;
bool supports_64bit() const { return m_supports_64bit; }
uint32_t command_slot_count() const { return m_command_slot_count; } uint32_t command_slot_count() const { return m_command_slot_count; }
private: private:
@@ -38,9 +39,8 @@ namespace Kernel
BAN::Array<AHCIDevice*, 32> m_devices; BAN::Array<AHCIDevice*, 32> m_devices;
bool m_supports_64bit { false };
uint32_t m_command_slot_count { 0 }; uint32_t m_command_slot_count { 0 };
friend class ATAController;
}; };
} }
@@ -32,8 +32,6 @@
namespace Kernel namespace Kernel
{ {
static constexpr uint32_t s_hba_prdt_count { 8 };
struct FISRegisterH2D struct FISRegisterH2D
{ {
uint8_t fis_type; // FIS_TYPE_REGISTER_H2D uint8_t fis_type; // FIS_TYPE_REGISTER_H2D
@@ -61,7 +59,8 @@ namespace Kernel
uint8_t control; uint8_t control;
uint8_t __reserved1[4]; uint8_t __reserved1[4];
} __attribute__((packed)); };
static_assert(sizeof(FISRegisterH2D) == 20);
struct FISRegisterD2H struct FISRegisterD2H
{ {
@@ -90,7 +89,8 @@ namespace Kernel
uint8_t __reserved3[2]; uint8_t __reserved3[2];
uint8_t __reserved4[4]; uint8_t __reserved4[4];
} __attribute__((packed)); };
static_assert(sizeof(FISRegisterD2H) == 20);
struct FISDataBI struct FISDataBI
{ {
@@ -102,7 +102,8 @@ namespace Kernel
uint8_t __reserved1[2]; uint8_t __reserved1[2];
uint32_t data[0]; // Payload (1 - 2048 dwords) uint32_t data[0]; // Payload (1 - 2048 dwords)
} __attribute__((packed)); };
static_assert(sizeof(FISDataBI) == 4);
struct SetDeviceBitsD2H struct SetDeviceBitsD2H
{ {
@@ -117,7 +118,8 @@ namespace Kernel
uint8_t error; uint8_t error;
uint32_t __reserved1; uint32_t __reserved1;
} __attribute__((packed)); };
static_assert(sizeof(SetDeviceBitsD2H) == 8);
struct PIOSetupD2H struct PIOSetupD2H
{ {
@@ -149,7 +151,8 @@ namespace Kernel
uint16_t tc; // Transfer count uint16_t tc; // Transfer count
uint8_t __reserved4[2]; uint8_t __reserved4[2];
} __attribute__((packed)); };
static_assert(sizeof(PIOSetupD2H) == 20);
struct DMASetupBI struct DMASetupBI
{ {
@@ -163,8 +166,8 @@ namespace Kernel
uint8_t __reserved1[2]; uint8_t __reserved1[2];
uint64_t dma_buffer_id; // DMA Buffer Identifier. Used to Identify DMA buffer in host memory. uint32_t dma_buffer_id_lo; // DMA Buffer Identifier. Used to Identify DMA buffer in host memory.
// SATA Spec says host specific and not in Spec. Trying AHCI spec might work. uint32_t dma_buffer_id_hi; // SATA Spec says host specific and not in Spec. Trying AHCI spec might work.
uint32_t __reserved2; uint32_t __reserved2;
@@ -173,7 +176,8 @@ namespace Kernel
uint32_t dma_transfer_count; // Number of bytes to transfer. Bit 0 must be 0 uint32_t dma_transfer_count; // Number of bytes to transfer. Bit 0 must be 0
uint32_t __reserved3; uint32_t __reserved3;
} __attribute__((packed)); };
static_assert(sizeof(DMASetupBI) == 28);
struct HBAPortMemorySpace struct HBAPortMemorySpace
{ {
@@ -196,7 +200,8 @@ namespace Kernel
uint32_t fbs; // FIS-based switch control uint32_t fbs; // FIS-based switch control
uint32_t __reserved1[11]; uint32_t __reserved1[11];
uint32_t vendor[4]; uint32_t vendor[4];
} __attribute__((packed)); };
static_assert(sizeof(HBAPortMemorySpace) == 128);
struct HBAGeneralMemorySpace struct HBAGeneralMemorySpace
{ {
@@ -217,7 +222,8 @@ namespace Kernel
uint8_t vendor[0x100-0xA0]; uint8_t vendor[0x100-0xA0];
HBAPortMemorySpace ports[0]; // 1 - 32 ports HBAPortMemorySpace ports[0]; // 1 - 32 ports
} __attribute__((packed)); };
static_assert(sizeof(HBAGeneralMemorySpace) == 256);
struct ReceivedFIS struct ReceivedFIS
{ {
@@ -235,7 +241,8 @@ namespace Kernel
uint8_t ufis[64]; uint8_t ufis[64];
uint8_t __reserved[0x100-0xA0]; uint8_t __reserved[0x100-0xA0];
} __attribute__((packed)); };
static_assert(sizeof(ReceivedFIS) == 256);
struct HBACommandHeader struct HBACommandHeader
{ {
@@ -252,13 +259,14 @@ namespace Kernel
uint16_t prdtl; // Physical region descriptor table length in entries uint16_t prdtl; // Physical region descriptor table length in entries
volatile uint32_t prdbc; // Physical region descriptor byte count transferred uint32_t prdbc; // Physical region descriptor byte count transferred
uint32_t ctba; // Command table descriptor base address uint32_t ctba; // Command table descriptor base address
uint32_t ctbau; // Command table descriptor base address upper 32 bits uint32_t ctbau; // Command table descriptor base address upper 32 bits
uint32_t __reserved1[4]; uint32_t __reserved1[4];
} __attribute__((packed)); };
static_assert(sizeof(HBACommandHeader) == 32);
struct HBAPRDTEntry struct HBAPRDTEntry
{ {
@@ -269,15 +277,17 @@ namespace Kernel
uint32_t dbc : 22; // Byte count, 4M max uint32_t dbc : 22; // Byte count, 4M max
uint32_t __reserved1 : 9; uint32_t __reserved1 : 9;
uint32_t i : 1; // Interrupt on completion uint32_t i : 1; // Interrupt on completion
} __attribute__((packed)); };
static_assert(sizeof(HBAPRDTEntry) == 16);
struct HBACommandTable struct HBACommandTable
{ {
uint8_t cfis[64]; uint8_t cfis[64];
uint8_t acmd[16]; uint8_t acmd[16];
uint8_t __reserved[48]; uint8_t __reserved[48];
HBAPRDTEntry prdt_entry[s_hba_prdt_count]; HBAPRDTEntry prdt_entry[0];
} __attribute__((packed)); };
static_assert(sizeof(HBACommandTable) == 128);
enum class AHCIPortType enum class AHCIPortType
{ {
@@ -20,30 +20,39 @@ namespace Kernel
, m_port(port) , m_port(port)
{ } { }
BAN::ErrorOr<void> initialize(); BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> allocate_buffers();
BAN::ErrorOr<void> rebase(); BAN::ErrorOr<void> rebase();
BAN::ErrorOr<void> read_identify_data(); BAN::ErrorOr<void> read_identify_data();
paddr_t read_paddr(volatile uint32_t& lo, volatile uint32_t& hi) const;
void write_paddr(volatile uint32_t& lo, volatile uint32_t& hi, paddr_t paddr);
bool can_use_buffer_directly(BAN::ConstByteSpan buffer) const;
virtual BAN::ErrorOr<void> read_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ByteSpan) override; virtual BAN::ErrorOr<void> read_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ByteSpan) override;
virtual BAN::ErrorOr<void> write_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ConstByteSpan) override; virtual BAN::ErrorOr<void> write_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ConstByteSpan) override;
BAN::ErrorOr<void> send_command_and_block(uint64_t lba, uint64_t sector_count, Command command); BAN::ErrorOr<size_t> send_command_sync(uint64_t lba, BAN::ConstByteSpan buffer, Command command);
BAN::Optional<uint32_t> find_free_command_slot(); BAN::ErrorOr<void> send_command_and_wait(uint32_t slot);
BAN::ErrorOr<uint32_t> find_free_command_slot();
void handle_irq(); void handle_irq();
BAN::ErrorOr<void> block_until_command_completed(uint32_t command_slot);
private: private:
Mutex m_mutex; static constexpr uint32_t m_max_hba_prdt_count { 64 };
BAN::Atomic<uint32_t> m_prev_is { 0 };
uint32_t m_free_slots { 0 };
BAN::RefPtr<AHCIController> m_controller; BAN::RefPtr<AHCIController> m_controller;
volatile HBAPortMemorySpace* const m_port; volatile HBAPortMemorySpace* const m_port;
BAN::UniqPtr<DMARegion> m_dma_region; BAN::UniqPtr<DMARegion> m_dma_region;
// Intermediate read/write buffer
// TODO: can we read straight to user buffer? Mutex m_temp_buffer_mutex;
BAN::UniqPtr<DMARegion> m_data_dma_region; BAN::UniqPtr<DMARegion> m_temp_buffer;
SpinLock m_command_lock;
ThreadBlocker m_command_blocker;
friend class AHCIController; friend class AHCIController;
}; };
+6 -4
View File
@@ -6,7 +6,6 @@
#include <kernel/BootInfo.h> #include <kernel/BootInfo.h>
#include <kernel/InterruptController.h> #include <kernel/InterruptController.h>
#include <kernel/IO.h> #include <kernel/IO.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
@@ -935,7 +934,7 @@ acpi_release_global_lock:
return false; return false;
} }
BAN::ErrorOr<void> ACPI::enter_acpi_mode(uint8_t mode) BAN::ErrorOr<void> ACPI::enter_acpi_mode()
{ {
ASSERT(!m_namespace); ASSERT(!m_namespace);
@@ -1014,7 +1013,7 @@ acpi_release_global_lock:
AML::Reference arg_ref; AML::Reference arg_ref;
arg_ref.node.type = AML::Node::Type::Integer; arg_ref.node.type = AML::Node::Type::Integer;
arg_ref.node.as.integer.value = mode; arg_ref.node.as.integer.value = InterruptController::get().is_using_apic() ? 1 : 0;
arg_ref.ref_count = 2; arg_ref.ref_count = 2;
BAN::Array<AML::Reference*, 7> arguments(nullptr); BAN::Array<AML::Reference*, 7> arguments(nullptr);
@@ -1022,7 +1021,7 @@ acpi_release_global_lock:
TRY(AML::method_call(pic_path, pic_node, BAN::move(arguments))); TRY(AML::method_call(pic_path, pic_node, BAN::move(arguments)));
} }
dprintln("Evaluated \\_PIC({})", mode); dprintln("Evaluated \\_PIC({})", InterruptController::get().is_using_apic() ? 1 : 0);
uint8_t irq = fadt().sci_int; uint8_t irq = fadt().sci_int;
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error()) if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error())
@@ -1098,6 +1097,8 @@ acpi_release_global_lock:
dprintln("Initialized ACPI interrupts"); dprintln("Initialized ACPI interrupts");
if (InterruptController::get().is_using_apic())
{
if (auto interrupt_link_devices_or_error = m_namespace->find_device_with_eisa_id("PNP0C0F"_sv); !interrupt_link_devices_or_error.is_error()) if (auto interrupt_link_devices_or_error = m_namespace->find_device_with_eisa_id("PNP0C0F"_sv); !interrupt_link_devices_or_error.is_error())
{ {
uint64_t routed_irq_mask = 0; uint64_t routed_irq_mask = 0;
@@ -1107,6 +1108,7 @@ acpi_release_global_lock:
dwarnln("failed to route interrupt link device: {}", ret.error()); dwarnln("failed to route interrupt link device: {}", ret.error());
dprintln("Routed interrupt link devices"); dprintln("Routed interrupt link devices");
} }
}
return {}; return {};
} }
+29 -23
View File
@@ -487,17 +487,12 @@ namespace Kernel
write_to_local_apic(LAPIC_EIO_REG, 0); write_to_local_apic(LAPIC_EIO_REG, 0);
} }
void APIC::enable_irq(uint8_t irq) void APIC::enable_irq(uint8_t irq, bool level_triggered)
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
const uint32_t gsi = m_irq_overrides[irq]; const uint32_t gsi = m_irq_overrides[irq];
ASSERT(m_used_gsis[gsi / 8] & (1 << (gsi % 8)));
{
int byte = gsi / 8;
int bit = gsi % 8;
ASSERT(m_reserved_gsis[byte] & (1 << bit));
}
IOAPIC* ioapic = nullptr; IOAPIC* ioapic = nullptr;
for (IOAPIC& io : m_io_apics) for (IOAPIC& io : m_io_apics)
@@ -515,8 +510,8 @@ namespace Kernel
RedirectionEntry redir; RedirectionEntry redir;
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2); redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2);
redir.hi_dword = ioapic->read(IOAPIC_REDIRS + pin * 2 + 1); redir.hi_dword = ioapic->read(IOAPIC_REDIRS + pin * 2 + 1);
ASSERT(redir.mask); // TODO: handle overlapping interrupts
redir.trigger_mode = level_triggered;
redir.vector = IRQ_VECTOR_BASE + irq; redir.vector = IRQ_VECTOR_BASE + irq;
redir.mask = 0; redir.mask = 0;
// FIXME: distribute IRQs more evenly? // FIXME: distribute IRQs more evenly?
@@ -528,14 +523,14 @@ namespace Kernel
bool APIC::is_in_service(uint8_t irq) bool APIC::is_in_service(uint8_t irq)
{ {
uint32_t dword = (irq + IRQ_VECTOR_BASE) / 32; const uint32_t dword = (irq + IRQ_VECTOR_BASE) / 32;
uint32_t bit = (irq + IRQ_VECTOR_BASE) % 32; const uint32_t bit = (irq + IRQ_VECTOR_BASE) % 32;
uint32_t isr = read_from_local_apic(LAPIC_IS_REG + dword * 0x10); const uint32_t isr = read_from_local_apic(LAPIC_IS_REG + dword * 0x10);
return isr & (1 << bit); return isr & (1 << bit);
} }
BAN::ErrorOr<void> APIC::reserve_irq(uint8_t irq) BAN::ErrorOr<void> APIC::reserve_irq(uint8_t irq, bool shared)
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
@@ -557,20 +552,26 @@ namespace Kernel
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
} }
int byte = gsi / 8; const uint8_t byte = gsi / 8;
int bit = gsi % 8; const uint8_t mask = 1 << (gsi % 8);
if (m_reserved_gsis[byte] & (1 << bit))
if (!shared && (m_excl_gsis[byte] & mask))
{ {
dwarnln("GSI {} is already reserved (IRQ {})", gsi, irq); dwarnln("GSI {} is already reserved as exclusive", gsi);
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EINVAL);
} }
m_reserved_gsis[byte] |= 1 << bit;
m_used_gsis[byte] |= mask;
if (!shared)
m_excl_gsis[byte] |= mask;
return {}; return {};
} }
// FIXME: rewrite gsi and vector reserving // FIXME: rewrite gsi and vector reserving
// this is a hack to allow direct GSI reservation // this is a hack to allow direct GSI reservation
BAN::ErrorOr<uint8_t> APIC::reserve_gsi(uint32_t gsi) BAN::ErrorOr<uint8_t> APIC::reserve_gsi(uint32_t gsi, bool shared)
{ {
size_t irq = 0; size_t irq = 0;
for (; irq < 0x100; irq++) for (; irq < 0x100; irq++)
@@ -583,7 +584,7 @@ namespace Kernel
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
} }
TRY(reserve_irq(irq)); TRY(reserve_irq(irq, shared));
return irq; return irq;
} }
@@ -591,6 +592,7 @@ namespace Kernel
BAN::Optional<uint8_t> APIC::get_free_irq() BAN::Optional<uint8_t> APIC::get_free_irq()
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
for (uint8_t irq = 0; irq < m_irq_count; irq++) for (uint8_t irq = 0; irq < m_irq_count; irq++)
{ {
const uint8_t gsi = m_irq_overrides[irq]; const uint8_t gsi = m_irq_overrides[irq];
@@ -609,12 +611,16 @@ namespace Kernel
continue; continue;
const uint8_t byte = gsi / 8; const uint8_t byte = gsi / 8;
const uint8_t bit = gsi % 8; const uint8_t mask = 1 << (gsi % 8);
if (m_reserved_gsis[byte] & (1 << bit))
if (m_used_gsis[byte] & mask)
continue; continue;
m_reserved_gsis[byte] |= 1 << bit; m_used_gsis[byte] |= mask;
m_excl_gsis[byte] |= mask;
return irq; return irq;
} }
return {}; return {};
} }
+13 -5
View File
@@ -182,13 +182,22 @@ namespace Kernel
m_bdl_region = TRY(DMARegion::create(bdl_size + buffer_size * m_used_bdl_entries)); m_bdl_region = TRY(DMARegion::create(bdl_size + buffer_size * m_used_bdl_entries));
memset(reinterpret_cast<void*>(m_bdl_region->vaddr()), 0x00, m_bdl_region->size()); memset(reinterpret_cast<void*>(m_bdl_region->vaddr()), 0x00, m_bdl_region->size());
if (m_bdl_region->paddr() + m_bdl_region->size() > BAN::numeric_limits<uint32_t>::max())
{
dwarnln("Could not allocate 32 bit dma buffer");
return BAN::Error::from_errno(EFAULT);
}
auto* bdl_entries = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr());
for (size_t i = 0; i < m_bdl_entries; i++) for (size_t i = 0; i < m_bdl_entries; i++)
{ {
auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[i]; bdl_entries[i] = {
entry.address = m_bdl_region->paddr() + bdl_size + (i % m_used_bdl_entries) * buffer_size; .address = static_cast<uint32_t>(m_bdl_region->paddr() + bdl_size + (i % m_used_bdl_entries) * buffer_size),
entry.samples = 0; .samples = 0,
entry.flags = 0; .flags = 1 << 15,
};
} }
bdl_entries[m_bdl_entries - 1].flags |= 1 << 14;
m_bus_master->write32(BusMasterRegister::PO_BDBAR, m_bdl_region->paddr()); m_bus_master->write32(BusMasterRegister::PO_BDBAR, m_bdl_region->paddr());
@@ -245,7 +254,6 @@ namespace Kernel
auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[m_bdl_head]; auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[m_bdl_head];
entry.samples = sample_frames * get_channels(); entry.samples = sample_frames * get_channels();
entry.flags = (1 << 15);
memcpy( memcpy(
reinterpret_cast<void*>(m_bdl_region->paddr_to_vaddr(entry.address)), reinterpret_cast<void*>(m_bdl_region->paddr_to_vaddr(entry.address)),
m_sample_data->get_data().data(), m_sample_data->get_data().data(),
+3 -3
View File
@@ -3,7 +3,7 @@
#include <kernel/Audio/HDAudio/Controller.h> #include <kernel/Audio/HDAudio/Controller.h>
#include <kernel/Device/DeviceNumbers.h> #include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Lock/SpinLockAsMutex.h> #include <kernel/Lock/BlockableSpinLock.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
@@ -65,8 +65,8 @@ namespace Kernel
while (m_sample_data->full()) while (m_sample_data->full())
{ {
SpinLockGuardAsMutex smutex(lock_guard); BlockableSpinLock block(m_spinlock);
TRY(Thread::current().block_or_eintr_indefinite(m_sample_data_blocker, &smutex)); TRY(Thread::current().block_or_eintr_indefinite(m_sample_data_blocker, &block));
} }
const size_t to_copy = BAN::Math::min(buffer.size(), m_sample_data->free()); const size_t to_copy = BAN::Math::min(buffer.size(), m_sample_data->free());
+3 -3
View File
@@ -1,8 +1,8 @@
#include <kernel/Audio/HDAudio/AudioFunctionGroup.h> #include <kernel/Audio/HDAudio/AudioFunctionGroup.h>
#include <kernel/Audio/HDAudio/Controller.h> #include <kernel/Audio/HDAudio/Controller.h>
#include <kernel/Audio/HDAudio/Registers.h> #include <kernel/Audio/HDAudio/Registers.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/MMIO.h> #include <kernel/MMIO.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
@@ -369,8 +369,8 @@ namespace Kernel
{ {
if (SystemTimer::get().ms_since_boot() > waketime_ms) if (SystemTimer::get().ms_since_boot() > waketime_ms)
return BAN::Error::from_errno(ETIMEDOUT); return BAN::Error::from_errno(ETIMEDOUT);
SpinLockGuardAsMutex smutex(sguard); BlockableSpinLock block(m_rb_lock);
m_rb_blocker.block_with_timeout_ms(10, &smutex); m_rb_blocker.block_with_timeout_ms(10, &block);
} }
const size_t offset = 2 * m_rirb.index * sizeof(uint32_t); const size_t offset = 2 * m_rirb.index * sizeof(uint32_t);
+3 -3
View File
@@ -1,6 +1,6 @@
#include <kernel/Epoll.h> #include <kernel/Epoll.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
namespace Kernel namespace Kernel
@@ -222,8 +222,8 @@ namespace Kernel
if (!m_ready_events.empty()) if (!m_ready_events.empty())
continue; continue;
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_ready_lock);
TRY(Thread::current().block_or_eintr_or_waketime_ns(m_thread_blocker, waketime_ns, false, &smutex)); TRY(Thread::current().block_or_eintr_or_waketime_ns(m_thread_blocker, waketime_ns, false, &block));
} }
return event_count; return event_count;
+3 -3
View File
@@ -7,8 +7,8 @@
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/TmpFS/Inode.h> #include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Input/InputDevice.h> #include <kernel/Input/InputDevice.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <kernel/Storage/StorageDevice.h> #include <kernel/Storage/StorageDevice.h>
@@ -77,8 +77,8 @@ namespace Kernel
bool expected = true; bool expected = true;
if (!devfs->m_should_drop_disk_cache.compare_exchange(expected, false)) if (!devfs->m_should_drop_disk_cache.compare_exchange(expected, false))
{ {
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(devfs->m_disk_cache_lock);
devfs->m_disk_cache_thread_blocker.block_indefinite(&smutex); devfs->m_disk_cache_thread_blocker.block_indefinite(&block);
continue; continue;
} }
} }
+16 -4
View File
@@ -624,7 +624,7 @@ namespace Kernel
continue; continue;
buffer.used = true; buffer.used = true;
return Ext2FS::BlockBufferWrapper { return Ext2FS::BlockBufferWrapper {
buffer.buffer.span(), buffer.buffer,
[](void* self, const uint8_t* buffer) { static_cast<BlockBufferManager*>(self)->destroy_callback(buffer); }, [](void* self, const uint8_t* buffer) { static_cast<BlockBufferManager*>(self)->destroy_callback(buffer); },
this this
}; };
@@ -635,11 +635,23 @@ namespace Kernel
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size) BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)
{ {
for (auto& buffer : m_buffers) m_buffer_data = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(),
{ KERNEL_OFFSET, BAN::numeric_limits<vaddr_t>::max() },
block_size * m_buffers.size(),
PageTable::ReadWrite | PageTable::Present,
false
));
auto buffer_data_span = BAN::ByteSpan { reinterpret_cast<uint8_t*>(m_buffer_data->vaddr()), m_buffer_data->size() };
for (size_t i = 0; i < m_buffers.size(); i++)
{ {
TRY(buffer.buffer.resize(block_size)); m_buffers[i] = {
buffer.used = false; .buffer = buffer_data_span.slice(i * block_size, block_size),
.used = false,
};
} }
return {}; return {};
} }
+15 -8
View File
@@ -413,10 +413,14 @@ namespace Kernel
extern "C" void cpp_ipi_handler() extern "C" void cpp_ipi_handler()
{ {
ASSERT(InterruptController::get().is_in_service(IRQ_IPI - IRQ_VECTOR_BASE)); if (!InterruptController::get().is_in_service(IRQ_IPI - IRQ_VECTOR_BASE))
InterruptController::get().eoi(IRQ_IPI - IRQ_VECTOR_BASE); return;
Processor::handle_ipi(); Processor::handle_ipi();
Processor::scheduler().reschedule_if_idle();
InterruptController::get().eoi(IRQ_IPI - IRQ_VECTOR_BASE);
Processor::scheduler().reschedule_if_needed();
} }
extern "C" void cpp_timer_handler() extern "C" void cpp_timer_handler()
@@ -429,13 +433,17 @@ namespace Kernel
asm volatile("cli; 1: hlt; jmp 1b"); asm volatile("cli; 1: hlt; jmp 1b");
} }
ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE)); if (!InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE))
InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE); return;
if (Processor::current_is_bsp()) if (Processor::current_is_bsp())
Process::update_alarm_queue(); Process::update_alarm_queue();
Processor::scheduler().on_timer_interrupt(); Processor::scheduler().on_timer_interrupt();
InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE);
Processor::scheduler().reschedule_if_needed();
} }
extern "C" void cpp_irq_handler(uint32_t irq) extern "C" void cpp_irq_handler(uint32_t irq)
@@ -453,15 +461,14 @@ namespace Kernel
if (!InterruptController::get().is_in_service(irq)) if (!InterruptController::get().is_in_service(irq))
return; return;
InterruptController::get().eoi(irq);
if (auto* handler = s_interruptables[irq]) if (auto* handler = s_interruptables[irq])
handler->handle_irq(); handler->handle_irq();
else else
dprintln("no handler for irq 0x{2H}", irq); dprintln("no handler for irq 0x{2H}", irq);
Processor::scheduler().reschedule_if_idle(); InterruptController::get().eoi(irq);
ASSERT(Thread::current().state() != Thread::State::Terminated); Processor::scheduler().reschedule_if_needed();
} }
extern "C" void cpp_check_signal() extern "C" void cpp_check_signal()
+9 -9
View File
@@ -3,7 +3,7 @@
#include <kernel/Device/DeviceNumbers.h> #include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/InputDevice.h> #include <kernel/Input/InputDevice.h>
#include <kernel/Lock/SpinLockAsMutex.h> #include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Terminal/TTY.h> #include <kernel/Terminal/TTY.h>
#include <LibInput/Joystick.h> #include <LibInput/Joystick.h>
@@ -245,8 +245,8 @@ namespace Kernel
while (m_event_count == 0) while (m_event_count == 0)
{ {
// FIXME: should m_mutex be unlocked? // FIXME: should m_mutex be unlocked?
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_event_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_event_thread_blocker, &smutex)); TRY(Thread::current().block_or_eintr_indefinite(m_event_thread_blocker, &block));
} }
memcpy(buffer.data(), &m_event_buffer[m_event_tail * m_event_size], m_event_size); memcpy(buffer.data(), &m_event_buffer[m_event_tail * m_event_size], m_event_size);
@@ -289,8 +289,8 @@ namespace Kernel
if (s_tty_keyboard_events.empty()) if (s_tty_keyboard_events.empty())
{ {
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(s_tty_keyboard_event_lock);
s_tty_keyboard_event_blocker.block_indefinite(&smutex); s_tty_keyboard_event_blocker.block_indefinite(&block);
continue; continue;
} }
@@ -350,8 +350,8 @@ namespace Kernel
return bytes; return bytes;
} }
SpinLockGuardAsMutex smutex(keyboard_guard); BlockableSpinLock block(s_keyboard_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &block));
} }
} }
@@ -407,8 +407,8 @@ namespace Kernel
return bytes; return bytes;
} }
SpinLockGuardAsMutex smutex(mouse_guard); BlockableSpinLock block(s_mouse_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &block));
} }
} }
+4 -4
View File
@@ -435,14 +435,14 @@ namespace Kernel::Input
devices[0] = { devices[0] = {
.type = acpi_devices[0].type, .type = acpi_devices[0].type,
.interrupt = acpi_devices[0].irq.value_or(PS2::INTERRUPT_FIRST_PORT) .interrupt = acpi_devices[0].irq.value_or(PS2::IRQ::DEVICE0)
}; };
if (acpi_devices.size() > 1) if (acpi_devices.size() > 1)
{ {
devices[1] = { devices[1] = {
.type = acpi_devices[1].type, .type = acpi_devices[1].type,
.interrupt = acpi_devices[1].irq.value_or(PS2::INTERRUPT_SECOND_PORT) .interrupt = acpi_devices[1].irq.value_or(PS2::IRQ::DEVICE1)
}; };
} }
} }
@@ -450,11 +450,11 @@ namespace Kernel::Input
{ {
devices[0] = { devices[0] = {
.type = DeviceType::Unknown, .type = DeviceType::Unknown,
.interrupt = PS2::INTERRUPT_FIRST_PORT, .interrupt = PS2::IRQ::DEVICE0,
}; };
devices[1] = { devices[1] = {
.type = DeviceType::Unknown, .type = DeviceType::Unknown,
.interrupt = PS2::INTERRUPT_SECOND_PORT, .interrupt = PS2::IRQ::DEVICE1,
}; };
} }
else else
-1
View File
@@ -1,4 +1,3 @@
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Networking/ARPTable.h> #include <kernel/Networking/ARPTable.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
+3 -3
View File
@@ -1,7 +1,7 @@
#include <kernel/IDT.h> #include <kernel/IDT.h>
#include <kernel/InterruptController.h> #include <kernel/InterruptController.h>
#include <kernel/IO.h> #include <kernel/IO.h>
#include <kernel/Lock/SpinLockAsMutex.h> #include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <kernel/MMIO.h> #include <kernel/MMIO.h>
#include <kernel/Networking/E1000/E1000.h> #include <kernel/Networking/E1000/E1000.h>
@@ -380,8 +380,8 @@ namespace Kernel
if (rx_current != rx_tail) if (rx_current != rx_tail)
write32(REG_RDT0, rx_tail); write32(REG_RDT0, rx_tail);
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_rx_lock);
m_rx_blocker.block_indefinite(&smutex); m_rx_blocker.block_indefinite(&block);
} }
m_thread_is_dead = true; m_thread_is_dead = true;
+1 -1
View File
@@ -1,6 +1,6 @@
#include <kernel/Lock/SpinLock.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Networking/ICMP.h> #include <kernel/Networking/ICMP.h>
#include <kernel/Networking/IPv4Layer.h> #include <kernel/Networking/IPv4Layer.h>
#include <kernel/Networking/NetworkManager.h> #include <kernel/Networking/NetworkManager.h>
+5 -5
View File
@@ -1,4 +1,4 @@
#include <kernel/Lock/SpinLockAsMutex.h> #include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Networking/Loopback.h> #include <kernel/Networking/Loopback.h>
#include <kernel/Networking/NetworkManager.h> #include <kernel/Networking/NetworkManager.h>
@@ -72,8 +72,8 @@ namespace Kernel
descriptor.state = 1; descriptor.state = 1;
return descriptor; return descriptor;
} }
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_buffer_lock);
m_thread_blocker.block_indefinite(&smutex); m_thread_blocker.block_indefinite(&block);
} }
}(); }();
@@ -118,8 +118,8 @@ namespace Kernel
m_thread_blocker.unblock(); m_thread_blocker.unblock();
} }
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_buffer_lock);
m_thread_blocker.block_indefinite(&smutex); m_thread_blocker.block_indefinite(&block);
} }
m_thread_is_dead = true; m_thread_is_dead = true;
+5 -5
View File
@@ -1,4 +1,4 @@
#include <kernel/Lock/SpinLockAsMutex.h> #include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Networking/NetworkManager.h> #include <kernel/Networking/NetworkManager.h>
#include <kernel/Networking/RTL8169/Definitions.h> #include <kernel/Networking/RTL8169/Definitions.h>
#include <kernel/Networking/RTL8169/RTL8169.h> #include <kernel/Networking/RTL8169/RTL8169.h>
@@ -218,8 +218,8 @@ namespace Kernel
SpinLockGuard guard(m_tx_lock); SpinLockGuard guard(m_tx_lock);
while (descriptor.command & RTL8169_DESC_CMD_OWN) while (descriptor.command & RTL8169_DESC_CMD_OWN)
{ {
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_tx_lock);
m_tx_blocker.block_indefinite(&smutex); m_tx_blocker.block_indefinite(&block);
} }
} }
@@ -308,8 +308,8 @@ namespace Kernel
m_rx_head = (m_rx_head + 1) % m_rx_descriptor_count; m_rx_head = (m_rx_head + 1) % m_rx_descriptor_count;
} }
SpinLockGuardAsMutex smutex(rx_lock_guard); BlockableSpinLock block(m_rx_lock);
m_rx_blocker.block_indefinite(&smutex); m_rx_blocker.block_indefinite(&block);
} }
m_rx_thread_is_dead = true; m_rx_thread_is_dead = true;
+3 -3
View File
@@ -1,5 +1,5 @@
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h> #include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Networking/UDPSocket.h> #include <kernel/Networking/UDPSocket.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
@@ -181,8 +181,8 @@ namespace Kernel
while (m_packets.empty()) while (m_packets.empty())
{ {
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_packet_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &smutex)); TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &block));
} }
auto packet_info = m_packets.front(); auto packet_info = m_packets.front();
+32
View File
@@ -354,6 +354,35 @@ namespace Kernel
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
} }
BAN::ErrorOr<long> OpenFileDescriptorSet::ioctl(int fd, unsigned long request, void* arg)
{
BAN::RefPtr<Inode> inode;
{
LockGuard _(m_mutex);
TRY(validate_fd(fd));
switch (request)
{
case FIONBIO:
{
int enabled;
TRY(read_from_user(arg, &enabled, sizeof(int)));
if (enabled)
m_open_files[fd]->status_flags |= O_NONBLOCK;
else
m_open_files[fd]->status_flags &= ~O_NONBLOCK;
return 0;
}
}
inode = m_open_files[fd]->file.inode;
}
return inode->ioctl(request, arg);
}
BAN::ErrorOr<off_t> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence) BAN::ErrorOr<off_t> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence)
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);
@@ -376,6 +405,9 @@ namespace Kernel
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
} }
if (BAN::Math::will_addition_overflow(base_offset, offset))
return BAN::Error::from_errno(EOVERFLOW);
const off_t new_offset = base_offset + offset; const off_t new_offset = base_offset + offset;
if (new_offset < 0) if (new_offset < 0)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
+58 -26
View File
@@ -45,6 +45,36 @@ namespace Kernel::PCI
}; };
static_assert(sizeof(MSIXEntry) == 16); static_assert(sizeof(MSIXEntry) == 16);
class PCIPinInterrupt : public Interruptable
{
public:
PCIPinInterrupt(uint8_t irq)
{
Interruptable::set_irq(irq);
InterruptController::get().enable_irq(irq, true);
}
void handle_irq() override
{
SpinLockGuard _(m_lock);
for (auto* interruptable : m_interruptables)
interruptable->handle_irq();
}
BAN::ErrorOr<void> add_interruptable(Interruptable* interruptable)
{
SpinLockGuard _(m_lock);
TRY(m_interruptables.push_back(interruptable));
return {};
}
private:
SpinLock m_lock;
BAN::Vector<Interruptable*> m_interruptables;
};
static BAN::HashMap<uint8_t, BAN::UniqPtr<PCIPinInterrupt>> s_pci_pin_interrupts;
static uint32_t get_device_io_address(uint8_t bus, uint8_t dev, uint8_t func) static uint32_t get_device_io_address(uint8_t bus, uint8_t dev, uint8_t func)
{ {
return 0x80000000 return 0x80000000
@@ -427,9 +457,6 @@ namespace Kernel::PCI
void PCI::Device::enable_interrupt(uint8_t index, Interruptable& interruptable) void PCI::Device::enable_interrupt(uint8_t index, Interruptable& interruptable)
{ {
const uint8_t irq = get_interrupt(index);
interruptable.set_irq(irq);
const auto disable_msi = const auto disable_msi =
[this]() [this]()
{ {
@@ -450,24 +477,33 @@ namespace Kernel::PCI
write_word(*m_offset_msi_x + 0x02, msg_ctrl); write_word(*m_offset_msi_x + 0x02, msg_ctrl);
}; };
const uint8_t irq = get_interrupt(index);
switch (m_interrupt_mechanism) switch (m_interrupt_mechanism)
{ {
case InterruptMechanism::NONE: case InterruptMechanism::NONE:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
case InterruptMechanism::PIN: case InterruptMechanism::PIN:
{
enable_pin_interrupts(); enable_pin_interrupts();
disable_msi(); disable_msi();
disable_msi_x(); disable_msi_x();
if (!InterruptController::get().is_using_apic()) // TODO: allow failing
write_byte(PCI_REG_IRQ_LINE, irq); auto it = s_pci_pin_interrupts.find(irq);
InterruptController::get().enable_irq(irq); if (it == s_pci_pin_interrupts.end())
it = MUST(s_pci_pin_interrupts.insert(irq, MUST(BAN::UniqPtr<PCIPinInterrupt>::create(irq))));
MUST(it->value->add_interruptable(&interruptable));
break; break;
}
case InterruptMechanism::MSI: case InterruptMechanism::MSI:
{ {
disable_pin_interrupts(); disable_pin_interrupts();
disable_msi_x(); disable_msi_x();
interruptable.set_irq(irq);
uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02); uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02);
msg_ctrl &= ~(0x07 << 4); // Only one interrupt msg_ctrl &= ~(0x07 << 4); // Only one interrupt
msg_ctrl |= 1u << 0; // Enable msg_ctrl |= 1u << 0; // Enable
@@ -495,6 +531,8 @@ namespace Kernel::PCI
disable_pin_interrupts(); disable_pin_interrupts();
disable_msi(); disable_msi();
interruptable.set_irq(irq);
uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02); uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
msg_ctrl |= 1 << 15; // Enable msg_ctrl |= 1 << 15; // Enable
write_word(*m_offset_msi_x + 0x02, msg_ctrl); write_word(*m_offset_msi_x + 0x02, msg_ctrl);
@@ -548,7 +586,7 @@ namespace Kernel::PCI
debug_guard.disable(); debug_guard.disable();
auto& apic = static_cast<APIC&>(InterruptController::get()); auto& apic = static_cast<APIC&>(InterruptController::get());
return TRY(apic.reserve_gsi(gsi_value)); return TRY(apic.reserve_gsi(gsi_value, true));
} }
else else
{ {
@@ -587,11 +625,8 @@ namespace Kernel::PCI
if (irq_mask & (1 << irq)) if (irq_mask & (1 << irq))
break; break;
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error()) if (auto ret = InterruptController::get().reserve_irq(irq, true); ret.is_error())
{
dwarnln("FIXME: irq sharing");
return ret.release_error(); return ret.release_error();
}
return irq; return irq;
} }
@@ -621,11 +656,8 @@ namespace Kernel::PCI
debug_guard.disable(); debug_guard.disable();
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error()) if (auto ret = InterruptController::get().reserve_irq(irq, true); ret.is_error())
{
dwarnln("FIXME: irq sharing");
return ret.release_error(); return ret.release_error();
}
return irq; return irq;
} }
@@ -747,16 +779,8 @@ namespace Kernel::PCI
const auto mechanism = const auto mechanism =
[this, count]() -> InterruptMechanism [this, count]() -> InterruptMechanism
{ {
if (!InterruptController::get().is_using_apic()) if (InterruptController::get().is_using_apic())
{ {
// FIXME: support multiple PIN interrupts
if (count == 1)
return InterruptMechanism::PIN;
// MSI cannot be used without LAPIC
return InterruptMechanism::NONE;
}
if (m_offset_msi_x.has_value()) if (m_offset_msi_x.has_value())
{ {
const uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02); const uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
@@ -770,6 +794,7 @@ namespace Kernel::PCI
return InterruptMechanism::MSI; return InterruptMechanism::MSI;
// FIXME: support multiple MSIs // FIXME: support multiple MSIs
} }
}
if (count == 1) if (count == 1)
return InterruptMechanism::PIN; return InterruptMechanism::PIN;
@@ -790,10 +815,17 @@ namespace Kernel::PCI
case InterruptMechanism::NONE: case InterruptMechanism::NONE:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
case InterruptMechanism::PIN: case InterruptMechanism::PIN:
if (!InterruptController::get().is_using_apic()) if (InterruptController::get().is_using_apic())
return InterruptController::get().get_free_irq(); {
if (auto ret = find_intx_interrupt(); !ret.is_error()) if (auto ret = find_intx_interrupt(); !ret.is_error())
return ret.release_value(); return ret.release_value();
}
else
{
if (const uint8_t irq = read_byte(PCI_REG_IRQ_LINE); irq != 0xFF)
if (!InterruptController::get().reserve_irq(irq, true).is_error())
return irq;
}
return {}; return {};
case InterruptMechanism::MSI: case InterruptMechanism::MSI:
case InterruptMechanism::MSIX: case InterruptMechanism::MSIX:
+31 -19
View File
@@ -2,8 +2,6 @@
#include <kernel/IO.h> #include <kernel/IO.h>
#include <kernel/PIC.h> #include <kernel/PIC.h>
#include <string.h>
#define PIC1_CMD 0x20 #define PIC1_CMD 0x20
#define PIC1_DATA 0x21 #define PIC1_DATA 0x21
#define PIC2_CMD 0xA0 #define PIC2_CMD 0xA0
@@ -76,48 +74,62 @@ namespace Kernel
IO::outb(PIC1_CMD, PIC_EOI); IO::outb(PIC1_CMD, PIC_EOI);
} }
void PIC::enable_irq(uint8_t irq) void PIC::enable_irq(uint8_t irq, bool level_triggered)
{ {
SpinLockGuard _(m_lock); if (level_triggered)
ASSERT(irq < 16); dprintln("no level triggered IRQs with PIC, using edge triggered");
ASSERT(m_reserved_irqs & (1 << irq));
uint16_t port = PIC1_DATA; SpinLockGuard _(m_lock);
if(irq >= 8)
{ ASSERT(irq < 16);
port = PIC2_DATA; ASSERT(m_used_irqs & (1 << irq));
const uint16_t port = [&irq]() -> uint16_t {
if (irq < 8)
return PIC1_DATA;
irq -= 8; irq -= 8;
} return PIC2_DATA;
}();
IO::outb(port, IO::inb(port) & ~(1 << irq)); IO::outb(port, IO::inb(port) & ~(1 << irq));
} }
BAN::ErrorOr<void> PIC::reserve_irq(uint8_t irq) BAN::ErrorOr<void> PIC::reserve_irq(uint8_t irq, bool shared)
{ {
if (irq >= 16) if (irq >= 16)
{ {
dwarnln("PIC only supports 16 irqs"); dwarnln("PIC only supports 16 irqs");
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EFAULT);
} }
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
if (m_reserved_irqs & (1 << irq))
if (!shared && (m_excl_irqs & (1 << irq)))
{ {
dwarnln("irq {} is already reserved", irq); dwarnln("IRQ {} is already reserved as exclusive", irq);
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EINVAL);
} }
m_reserved_irqs |= 1 << irq;
m_used_irqs |= 1 << irq;
if (!shared)
m_excl_irqs |= 1 << irq;
return {}; return {};
} }
BAN::Optional<uint8_t> PIC::get_free_irq() BAN::Optional<uint8_t> PIC::get_free_irq()
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
for (int irq = 0; irq < 16; irq++)
for (uint8_t irq = 0; irq < 16; irq++)
{ {
if (m_reserved_irqs & (1 << irq)) if (m_used_irqs & (1 << irq))
continue; continue;
m_reserved_irqs |= 1 << irq; m_used_irqs |= 1 << irq;
m_excl_irqs |= 1 << irq;
return irq; return irq;
} }
return {}; return {};
} }
+6 -7
View File
@@ -10,8 +10,8 @@
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/IDT.h> #include <kernel/IDT.h>
#include <kernel/InterruptController.h> #include <kernel/InterruptController.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Memory/FileBackedRegion.h> #include <kernel/Memory/FileBackedRegion.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/MemoryBackedRegion.h> #include <kernel/Memory/MemoryBackedRegion.h>
@@ -1197,8 +1197,8 @@ namespace Kernel
if (options & WNOHANG) if (options & WNOHANG)
return 0; return 0;
SpinLockGuardAsMutex smutex(sguard); BlockableSpinLock block(m_child_wait_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_child_wait_blocker, &smutex)); TRY(Thread::current().block_or_eintr_indefinite(m_child_wait_blocker, &block));
} }
if (user_stat_loc != nullptr) if (user_stat_loc != nullptr)
@@ -2049,8 +2049,7 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, unsigned long request, void* arg) BAN::ErrorOr<long> Process::sys_ioctl(int fildes, unsigned long request, void* arg)
{ {
auto inode = TRY(m_open_file_descriptors.inode_of(fildes)); return m_open_file_descriptors.ioctl(fildes, request, arg);
return TRY(inode->ioctl(request, arg));
} }
BAN::ErrorOr<long> Process::sys_pselect(sys_pselect_t* user_arguments) BAN::ErrorOr<long> Process::sys_pselect(sys_pselect_t* user_arguments)
@@ -3172,8 +3171,8 @@ namespace Kernel
if (!m_stopped) if (!m_stopped)
break; break;
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_signal_lock);
m_stop_blocker.block_indefinite(&smutex); m_stop_blocker.block_indefinite(&block);
} }
} }
+2
View File
@@ -447,6 +447,8 @@ namespace Kernel
auto processor_id = current_id(); auto processor_id = current_id();
auto& processor = s_processors[processor_id.m_id]; auto& processor = s_processors[processor_id.m_id];
ASSERT(!processor.m_smp_messages_disabled);
auto* pending = processor.m_smp_pending.exchange(nullptr); auto* pending = processor.m_smp_pending.exchange(nullptr);
if (pending == nullptr) if (pending == nullptr)
return set_interrupt_state(state); return set_interrupt_state(state);
+22 -19
View File
@@ -235,8 +235,12 @@ namespace Kernel
add_current_to_most_loaded(m_current->blocked ? &m_block_queue : &m_run_queue); add_current_to_most_loaded(m_current->blocked ? &m_block_queue : &m_run_queue);
if (!m_current->blocked) if (!m_current->blocked)
m_run_queue.add_thread_to_back(m_current); m_run_queue.add_thread_to_back(m_current);
else if (m_block_queue.add_thread_with_wake_time(m_current)) else
{
if (m_block_queue.add_thread_with_wake_time(m_current))
update_wake_up_deadline(); update_wake_up_deadline();
Processor::set_disable_smp_messages(false);
}
break; break;
case Thread::State::NotStarted: case Thread::State::NotStarted:
ASSERT(!m_current->blocked); ASSERT(!m_current->blocked);
@@ -306,14 +310,7 @@ namespace Kernel
const uint64_t current_ns = SystemTimer::get().ns_since_boot(); const uint64_t current_ns = SystemTimer::get().ns_since_boot();
while (!m_block_queue.empty() && current_ns >= m_block_queue.front()->wake_time_ns) while (!m_block_queue.empty() && current_ns >= m_block_queue.front()->wake_time_ns)
{ unblock_thread(m_block_queue.front());
auto* node = m_block_queue.pop_front();
if (auto* blocker = node->blocker.load())
blocker->remove_thread_from_block_queue(node);
node->blocked = false;
update_most_loaded_node_queue(node, &m_run_queue);
m_run_queue.add_thread_to_back(node);
}
} }
void Scheduler::update_wake_up_deadline() void Scheduler::update_wake_up_deadline()
@@ -335,13 +332,16 @@ namespace Kernel
static_cast<APIC&>(interrupt_controller).set_timer_dealine(deadline_ns); static_cast<APIC&>(interrupt_controller).set_timer_dealine(deadline_ns);
} }
void Scheduler::reschedule_if_idle() void Scheduler::reschedule_if_needed()
{ {
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled); ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
if (m_current == nullptr && !m_run_queue.empty()) if ((is_idle() && !m_run_queue.empty()) || m_has_pending_reschedule)
{
m_has_pending_reschedule = false;
Processor::yield(); Processor::yield();
} }
}
extern "C" void scheduler_on_yield_trampoline(YieldRegisters* yield_registers) extern "C" void scheduler_on_yield_trampoline(YieldRegisters* yield_registers)
{ {
@@ -369,7 +369,7 @@ namespace Kernel
// NOTE: yield will update the timer deadline, but if we do not yield make sure // NOTE: yield will update the timer deadline, but if we do not yield make sure
// we set the next deadline or we won't get another timer interrupt // we set the next deadline or we won't get another timer interrupt
if (is_idle() || SystemTimer::get().ns_since_boot() >= m_next_reschedule_ns) if (is_idle() || SystemTimer::get().ns_since_boot() >= m_next_reschedule_ns)
Processor::yield(); m_has_pending_reschedule = true;
else else
update_wake_up_deadline(); update_wake_up_deadline();
} }
@@ -383,14 +383,15 @@ namespace Kernel
{ {
if (!node->blocked) if (!node->blocked)
return; return;
if (node != m_current) ASSERT(node != m_current);
Processor::set_disable_smp_messages(true);
m_block_queue.remove_node(node); m_block_queue.remove_node(node);
if (auto* blocker = node->blocker.load()) if (auto* blocker = node->blocker.load())
blocker->remove_thread_from_block_queue(node); blocker->remove_thread_from_block_queue(node);
node->blocked = false; node->blocked = false;
if (node != m_current)
m_run_queue.add_thread_to_back(node); m_run_queue.add_thread_to_back(node);
update_most_loaded_node_queue(node, &m_run_queue); update_most_loaded_node_queue(node, &m_run_queue);
Processor::set_disable_smp_messages(false);
} }
else else
{ {
@@ -602,7 +603,6 @@ namespace Kernel
} }
thread_info.node->processor_id = least_loaded_id; thread_info.node->processor_id = least_loaded_id;
Processor::send_smp_message(least_loaded_id, { Processor::send_smp_message(least_loaded_id, {
.type = Processor::SMPMessage::Type::NewThread, .type = Processor::SMPMessage::Type::NewThread,
.new_thread = thread_info.node .new_thread = thread_info.node
@@ -670,24 +670,27 @@ namespace Kernel
void Scheduler::block_current_thread(ThreadBlocker* blocker, uint64_t wake_time_ns, BaseMutex* mutex) void Scheduler::block_current_thread(ThreadBlocker* blocker, uint64_t wake_time_ns, BaseMutex* mutex)
{ {
if (SystemTimer::get().ns_since_boot() >= wake_time_ns)
return;
auto state = Processor::get_interrupt_state(); auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled); Processor::set_interrupt_state(InterruptState::Disabled);
ASSERT(m_current->processor_id == Processor::current_id()); ASSERT(m_current->processor_id == Processor::current_id());
ASSERT(!m_current->blocked); ASSERT(!m_current->blocked);
Processor::set_disable_smp_messages(true);
m_current->blocked = true; m_current->blocked = true;
m_current->wake_time_ns = wake_time_ns; m_current->wake_time_ns = wake_time_ns;
if (blocker) if (blocker != nullptr)
blocker->add_thread_to_block_queue(m_current); blocker->add_thread_to_block_queue(m_current);
update_most_loaded_node_queue(m_current, &m_block_queue);
uint32_t lock_depth = 0; uint32_t lock_depth = 0;
if (mutex != nullptr) if (mutex != nullptr)
{ {
ASSERT(mutex->is_locked() && mutex->locker() == m_current->thread->tid()); ASSERT(mutex->is_locked_by_current_thread());
lock_depth = mutex->lock_depth(); lock_depth = mutex->lock_depth();
} }
+13 -11
View File
@@ -39,6 +39,7 @@ namespace Kernel
m_pci_device.enable_interrupt(0, *this); m_pci_device.enable_interrupt(0, *this);
abar_mem.ghc = abar_mem.ghc | SATA_GHC_INTERRUPT_ENABLE; abar_mem.ghc = abar_mem.ghc | SATA_GHC_INTERRUPT_ENABLE;
m_supports_64bit = !!(abar_mem.cap & (1u << 31));
m_command_slot_count = ((abar_mem.cap >> 8) & 0x1F) + 1; m_command_slot_count = ((abar_mem.cap >> 8) & 0x1F) + 1;
uint32_t pi = abar_mem.pi; uint32_t pi = abar_mem.pi;
@@ -85,28 +86,29 @@ namespace Kernel
void AHCIController::handle_irq() void AHCIController::handle_irq()
{ {
auto& abar_mem = *(volatile HBAGeneralMemorySpace*)m_abar->vaddr(); auto& abar_mem = *reinterpret_cast<volatile HBAGeneralMemorySpace*>(m_abar->vaddr());
const uint32_t is = abar_mem.is; while (uint32_t is = abar_mem.is)
{
abar_mem.is = is; abar_mem.is = is;
for (uint8_t i = 0; i < 32; i++) while (is != 0)
{ {
if (is & (1 << i)) const size_t idx = __builtin_ctz(is);
{ if (auto& device = m_devices[idx])
if (m_devices[i]) device->handle_irq();
m_devices[i]->handle_irq();
else else
dwarnln("ignoring interrupt to device {}", i); dwarnln("ignoring interrupt for port {}", idx);
is &= ~(1u << idx);
} }
} }
} }
BAN::Optional<AHCIPortType> AHCIController::check_port_type(volatile HBAPortMemorySpace& port) BAN::Optional<AHCIPortType> AHCIController::check_port_type(volatile HBAPortMemorySpace& port)
{ {
uint32_t ssts = port.ssts; const uint32_t ssts = port.ssts;
uint8_t ipm = (ssts >> 8) & 0x0F; const uint8_t ipm = (ssts >> 8) & 0x0F;
uint8_t det = (ssts >> 0) & 0x0F; const uint8_t det = (ssts >> 0) & 0x0F;
if (det != HBA_PORT_DET_PRESENT) if (det != HBA_PORT_DET_PRESENT)
return {}; return {};
+254 -119
View File
@@ -11,6 +11,13 @@ namespace Kernel
static constexpr uint64_t s_ata_timeout_ms = 1000; static constexpr uint64_t s_ata_timeout_ms = 1000;
static constexpr size_t align_up_to(size_t value, size_t alignment)
{
if (const size_t rem = value % alignment)
value += alignment - rem;
return value;
}
static void start_cmd(volatile HBAPortMemorySpace* port) static void start_cmd(volatile HBAPortMemorySpace* port)
{ {
while (port->cmd & HBA_PxCMD_CR) while (port->cmd & HBA_PxCMD_CR)
@@ -27,6 +34,27 @@ namespace Kernel
continue; continue;
} }
paddr_t AHCIDevice::read_paddr(volatile uint32_t& lo, volatile uint32_t& hi) const
{
if (!m_controller->supports_64bit())
return lo;
return (static_cast<uint64_t>(hi) << 32) | lo;
}
void AHCIDevice::write_paddr(volatile uint32_t& lo, volatile uint32_t& hi, paddr_t paddr)
{
if (!m_controller->supports_64bit())
{
ASSERT((paddr >> 32) == 0);
lo = paddr;
}
else
{
lo = paddr & 0xFFFFFFFF;
hi = paddr >> 32;
}
}
BAN::ErrorOr<BAN::RefPtr<AHCIDevice>> AHCIDevice::create(BAN::RefPtr<AHCIController> controller, volatile HBAPortMemorySpace* port) BAN::ErrorOr<BAN::RefPtr<AHCIDevice>> AHCIDevice::create(BAN::RefPtr<AHCIController> controller, volatile HBAPortMemorySpace* port)
{ {
auto* device_ptr = new AHCIDevice(controller, port); auto* device_ptr = new AHCIDevice(controller, port);
@@ -37,57 +65,61 @@ namespace Kernel
BAN::ErrorOr<void> AHCIDevice::initialize() BAN::ErrorOr<void> AHCIDevice::initialize()
{ {
TRY(allocate_buffers());
TRY(rebase()); TRY(rebase());
m_temp_buffer = TRY(DMARegion::create(256 * 1024, PageTable::MemoryType::Normal));
memset(reinterpret_cast<void*>(m_temp_buffer->vaddr()), 0x00, m_temp_buffer->size());
if (!m_controller->supports_64bit() && m_temp_buffer->paddr() + m_temp_buffer->size() > 0x100000000)
{
dwarnln("cannot allocate 32 bit buffer and the controller does not support 64 bit");
return BAN::Error::from_errno(EFAULT);
}
if (const uint32_t command_slots = m_controller->command_slot_count(); command_slots < 32)
m_free_slots = (1u << command_slots) - 1;
else
m_free_slots = -1;
// enable interrupts // enable interrupts
m_port->ie = 0xFFFFFFFF; m_port->ie = 0xFFFFFFFF;
TRY(read_identify_data()); TRY(read_identify_data());
TRY(detail::ATABaseDevice::initialize({ (const uint16_t*)m_data_dma_region->vaddr(), m_data_dma_region->size() / sizeof(uint16_t) })); TRY(detail::ATABaseDevice::initialize({ reinterpret_cast<const uint16_t*>(m_temp_buffer->vaddr()), 256 }));
return {};
}
BAN::ErrorOr<void> AHCIDevice::allocate_buffers()
{
uint32_t command_slot_count = m_controller->command_slot_count();
size_t needed_bytes = (sizeof(HBACommandHeader) + sizeof(HBACommandTable)) * command_slot_count + sizeof(ReceivedFIS);
m_dma_region = TRY(DMARegion::create(needed_bytes));
memset((void*)m_dma_region->vaddr(), 0x00, m_dma_region->size());
m_data_dma_region = TRY(DMARegion::create(PAGE_SIZE));
memset((void*)m_data_dma_region->vaddr(), 0x00, m_data_dma_region->size());
return {}; return {};
} }
BAN::ErrorOr<void> AHCIDevice::rebase() BAN::ErrorOr<void> AHCIDevice::rebase()
{ {
ASSERT(m_dma_region); const uint32_t command_slot_count = m_controller->command_slot_count();
uint32_t command_slot_count = m_controller->command_slot_count(); const size_t command_list_size = command_slot_count * sizeof(HBACommandHeader);
const size_t command_table_offset = align_up_to(command_list_size, 128);
const size_t command_table_entry_size = align_up_to(sizeof(HBACommandTable) + m_max_hba_prdt_count * sizeof(HBAPRDTEntry), 128);
const size_t fis_offset = align_up_to(command_table_offset + command_slot_count * command_table_entry_size, 256);
m_dma_region = TRY(DMARegion::create(fis_offset + sizeof(ReceivedFIS)));
if (!m_controller->supports_64bit() && m_dma_region->paddr() + m_dma_region->size() > 0x100000000)
{
dwarnln("cannot allocate 32 bit buffer and the controller does not support 64 bit");
return BAN::Error::from_errno(EFAULT);
}
memset(reinterpret_cast<void*>(m_dma_region->vaddr()), 0x00, m_dma_region->size());
stop_cmd(m_port); stop_cmd(m_port);
uint64_t fis_paddr = m_dma_region->paddr(); const paddr_t command_list_paddr = m_dma_region->paddr();
m_port->fb = fis_paddr & 0xFFFFFFFF; write_paddr(m_port->clb, m_port->clbu, command_list_paddr);
m_port->fbu = fis_paddr >> 32;
uint64_t command_list_paddr = fis_paddr + sizeof(ReceivedFIS); volatile auto* command_list = reinterpret_cast<volatile HBACommandHeader*>(m_dma_region->paddr_to_vaddr(command_list_paddr));
m_port->clb = command_list_paddr & 0xFFFFFFFF; const paddr_t command_table_base = command_list_paddr + command_slot_count * sizeof(HBACommandHeader);
m_port->clbu = command_list_paddr >> 32; for (uint32_t slot = 0; slot < command_slot_count; slot++)
write_paddr(command_list[slot].ctba, command_list[slot].ctbau, command_table_base + slot * command_table_entry_size);
auto* command_headers = (HBACommandHeader*)m_dma_region->paddr_to_vaddr(command_list_paddr); write_paddr(m_port->fb, m_port->fbu, m_dma_region->paddr() + fis_offset);
paddr_t command_table_paddr = command_list_paddr + command_slot_count * sizeof(HBACommandHeader);
for (uint32_t i = 0; i < command_slot_count; i++)
{
uint64_t command_table_entry_paddr = command_table_paddr + i * sizeof(HBACommandTable);
command_headers[i].prdtl = s_hba_prdt_count;
command_headers[i].ctba = command_table_entry_paddr & 0xFFFFFFFF;
command_headers[i].ctbau = command_table_entry_paddr >> 32;
}
start_cmd(m_port); start_cmd(m_port);
@@ -96,37 +128,26 @@ namespace Kernel
BAN::ErrorOr<void> AHCIDevice::read_identify_data() BAN::ErrorOr<void> AHCIDevice::read_identify_data()
{ {
ASSERT(m_data_dma_region); const auto slot = TRY(find_free_command_slot());
m_port->is = ~(uint32_t)0; const vaddr_t command_header_vaddr = m_dma_region->paddr_to_vaddr(read_paddr(m_port->clb, m_port->clbu));
volatile auto& command_header = reinterpret_cast<volatile HBACommandHeader*>(command_header_vaddr)[slot];
auto slot = find_free_command_slot();
ASSERT(slot.has_value());
volatile auto& command_header = reinterpret_cast<volatile HBACommandHeader*>(m_dma_region->paddr_to_vaddr(m_port->clb))[slot.value()];
command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t); command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t);
command_header.w = 0; command_header.w = 0;
command_header.prdtl = 1; command_header.prdtl = 1;
volatile auto& command_table = *reinterpret_cast<volatile HBACommandTable*>(m_dma_region->paddr_to_vaddr(command_header.ctba)); const vaddr_t command_table_vaddr = m_dma_region->paddr_to_vaddr(read_paddr(command_header.ctba, command_header.ctbau));
memset(const_cast<HBACommandTable*>(&command_table), 0x00, sizeof(HBACommandTable)); volatile auto& command_table = *reinterpret_cast<volatile HBACommandTable*>(command_table_vaddr);
command_table.prdt_entry[0].dba = m_data_dma_region->paddr(); write_paddr(command_table.prdt_entry[0].dba, command_table.prdt_entry[0].dbau, m_temp_buffer->paddr());
command_table.prdt_entry[0].dbc = 511; command_table.prdt_entry[0].dbc = 511;
command_table.prdt_entry[0].i = 1; command_table.prdt_entry[0].i = 1;
volatile auto& command = *reinterpret_cast<volatile FISRegisterH2D*>(command_table.cfis); volatile auto& command = *reinterpret_cast<volatile FISRegisterH2D*>(&command_table.cfis[0]);
command.fis_type = FIS_TYPE_REGISTER_H2D; command.fis_type = FIS_TYPE_REGISTER_H2D;
command.c = 1; command.c = 1;
command.command = ATA_COMMAND_IDENTIFY; command.command = ATA_COMMAND_IDENTIFY;
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + s_ata_timeout_ms; TRY(send_command_and_wait(slot));
while (m_port->tfd & (ATA_STATUS_BSY | ATA_STATUS_DRQ))
if (SystemTimer::get().ms_since_boot() >= timeout_ms)
return BAN::Error::from_errno(ETIMEDOUT);
m_port->ci = 1 << slot.value();
TRY(block_until_command_completed(slot.value()));
return {}; return {};
} }
@@ -150,49 +171,64 @@ namespace Kernel
void AHCIDevice::handle_irq() void AHCIDevice::handle_irq()
{ {
const uint32_t is = m_port->is; while (const uint32_t is = m_port->is)
{
m_prev_is |= is;
m_port->is = is; m_port->is = is;
const uint32_t serr = m_port->serr; SpinLockGuard _(m_command_lock);
m_command_blocker.unblock();
}
if (const uint32_t serr = m_port->serr & 0xFFFF)
{
m_port->serr = serr; m_port->serr = serr;
if (auto err = serr & 0xFFFF) print_error(serr);
print_error(err); }
} }
BAN::ErrorOr<void> AHCIDevice::block_until_command_completed(uint32_t command_slot) bool AHCIDevice::can_use_buffer_directly(BAN::ConstByteSpan buffer) const
{ {
static constexpr uint64_t poll_timeout_ms = 10; const vaddr_t buffer_vaddr = reinterpret_cast<vaddr_t>(buffer.data());
if (buffer_vaddr % 2)
return false;
const auto start_time_ms = SystemTimer::get().ms_since_boot(); if (m_controller->supports_64bit())
return true;
while (SystemTimer::get().ms_since_boot() < start_time_ms + poll_timeout_ms) const vaddr_t buffer_base = buffer_vaddr & PAGE_ADDR_MASK;
if (!(m_port->ci & (1 << command_slot))) for (size_t off = 0; off < buffer.size(); off++)
return {}; if (PageTable::kernel().physical_address_of(buffer_base + off) >= 0x100000000)
return false;
// FIXME: This should actually block once ThreadBlocker support blocking with timeout. return true;
// This doesn't allow scheduler to go properly idle.
while (SystemTimer::get().ms_since_boot() < start_time_ms + s_ata_timeout_ms)
{
Processor::yield();
if (!(m_port->ci & (1 << command_slot)))
return {};
}
return BAN::Error::from_errno(ETIMEDOUT);
} }
BAN::ErrorOr<void> AHCIDevice::read_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ByteSpan buffer) BAN::ErrorOr<void> AHCIDevice::read_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ByteSpan buffer)
{ {
LockGuard _(m_mutex);
ASSERT(buffer.size() >= sector_count * sector_size()); ASSERT(buffer.size() >= sector_count * sector_size());
const size_t sectors_per_page = PAGE_SIZE / sector_size(); if (buffer.size() > sector_count * sector_size())
for (uint64_t sector_off = 0; sector_off < sector_count; sector_off += sectors_per_page) buffer = buffer.slice(0, sector_count * sector_size());
{
uint64_t to_read = BAN::Math::min<uint64_t>(sector_count - sector_off, sectors_per_page);
TRY(send_command_and_block(lba + sector_off, to_read, Command::Read)); if (can_use_buffer_directly(buffer))
memcpy(buffer.data() + sector_off * sector_size(), (void*)m_data_dma_region->vaddr(), to_read * sector_size()); {
size_t sectors_done = 0;
while (sectors_done < sector_count)
sectors_done += TRY(send_command_sync(lba + sectors_done, buffer.slice(sectors_done * sector_size()), Command::Read));
}
else
{
LockGuard _(m_temp_buffer_mutex);
uint8_t* const temp_buffer = reinterpret_cast<uint8_t*>(m_temp_buffer->vaddr());
while (!buffer.empty())
{
const size_t max_bytes = BAN::Math::min(buffer.size(), m_temp_buffer->size());
const size_t sectors = TRY(send_command_sync(lba, { temp_buffer, max_bytes }, Command::Read));
memcpy(buffer.data(), temp_buffer, sectors * sector_size());
buffer = buffer.slice(sectors * sector_size());
lba += sectors;
}
} }
return {}; return {};
@@ -200,37 +236,43 @@ namespace Kernel
BAN::ErrorOr<void> AHCIDevice::write_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ConstByteSpan buffer) BAN::ErrorOr<void> AHCIDevice::write_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ConstByteSpan buffer)
{ {
LockGuard _(m_mutex);
ASSERT(buffer.size() >= sector_count * sector_size()); ASSERT(buffer.size() >= sector_count * sector_size());
const size_t sectors_per_page = PAGE_SIZE / sector_size(); if (buffer.size() > sector_count * sector_size())
for (uint64_t sector_off = 0; sector_off < sector_count; sector_off += sectors_per_page) buffer = buffer.slice(0, sector_count * sector_size());
{
uint64_t to_read = BAN::Math::min<uint64_t>(sector_count - sector_off, sectors_per_page);
memcpy((void*)m_data_dma_region->vaddr(), buffer.data() + sector_off * sector_size(), to_read * sector_size()); if (can_use_buffer_directly(buffer))
TRY(send_command_and_block(lba + sector_off, to_read, Command::Write)); {
size_t sectors_done = 0;
while (sectors_done < sector_count)
sectors_done += TRY(send_command_sync(lba + sectors_done, buffer.slice(sectors_done * sector_size()), Command::Write));
}
else
{
LockGuard _(m_temp_buffer_mutex);
uint8_t* const temp_buffer = reinterpret_cast<uint8_t*>(m_temp_buffer->vaddr());
while (!buffer.empty())
{
const size_t max_bytes = BAN::Math::min(buffer.size(), m_temp_buffer->size());
memcpy(temp_buffer, buffer.data(), max_bytes);
const size_t sectors = TRY(send_command_sync(lba, { temp_buffer, max_bytes }, Command::Write));
buffer = buffer.slice(sectors * sector_size());
lba += sectors;
}
} }
return {}; return {};
} }
BAN::ErrorOr<void> AHCIDevice::send_command_and_block(uint64_t lba, uint64_t sector_count, Command command) BAN::ErrorOr<size_t> AHCIDevice::send_command_sync(uint64_t lba, BAN::ConstByteSpan buffer, Command command)
{ {
ASSERT(m_dma_region); ASSERT(m_dma_region);
ASSERT(m_data_dma_region);
ASSERT(0 < sector_count && sector_count <= 0xFFFF + 1);
ASSERT(sector_count * sector_size() <= m_data_dma_region->size()); const auto slot = TRY(find_free_command_slot());
m_port->is = ~(uint32_t)0; const vaddr_t command_header_vaddr = m_dma_region->paddr_to_vaddr(read_paddr(m_port->clb, m_port->clbu));
volatile auto& command_header = reinterpret_cast<volatile HBACommandHeader*>(command_header_vaddr)[slot];
auto slot = find_free_command_slot();
ASSERT(slot.has_value());
volatile auto& command_header = reinterpret_cast<volatile HBACommandHeader*>(m_dma_region->paddr_to_vaddr(m_port->clb))[slot.value()];
command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t); command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t);
command_header.prdtl = 1;
switch (command) switch (command)
{ {
case Command::Read: case Command::Read:
@@ -243,20 +285,66 @@ namespace Kernel
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
volatile auto& command_table = *reinterpret_cast<HBACommandTable*>(m_dma_region->paddr_to_vaddr(command_header.ctba)); const vaddr_t command_table_vaddr = m_dma_region->paddr_to_vaddr(read_paddr(command_header.ctba, command_header.ctbau));
memset(const_cast<HBACommandTable*>(&command_table), 0x00, sizeof(HBACommandTable)); volatile auto& command_table = *reinterpret_cast<volatile HBACommandTable*>(command_table_vaddr);
uint64_t data_dma_paddr64 = m_data_dma_region->paddr();
command_table.prdt_entry[0].dba = data_dma_paddr64 & 0xFFFFFFFF;
command_table.prdt_entry[0].dbau = data_dma_paddr64 >> 32;
command_table.prdt_entry[0].dbc = sector_count * sector_size() - 1;
command_table.prdt_entry[0].i = 1;
volatile auto& fis_command = *reinterpret_cast<volatile FISRegisterH2D*>(command_table.cfis); size_t prdt_count = 0;
memset(const_cast<FISRegisterH2D*>(&fis_command), 0x00, sizeof(FISRegisterH2D)); size_t total_bytes = 0;
paddr_t extend_paddr = 0;
while (!buffer.empty())
{
const auto to_paddr = [](vaddr_t vaddr) -> paddr_t {
return PageTable::kernel().physical_address_of(vaddr & PAGE_ADDR_MASK) + (vaddr % PAGE_SIZE);
};
const vaddr_t buffer_vaddr = reinterpret_cast<vaddr_t>(buffer.data());
const paddr_t buffer_paddr = to_paddr(buffer_vaddr);
const size_t bytes = BAN::Math::min(buffer.size(), PAGE_SIZE - buffer_vaddr % PAGE_SIZE);
bool can_extend = true;
if (prdt_count == 0)
can_extend = false;
else if (buffer_paddr != extend_paddr)
can_extend = false;
else if (command_table.prdt_entry[prdt_count - 1].dbc + bytes >= 0x400000)
can_extend = false;
if (can_extend)
command_table.prdt_entry[prdt_count - 1].dbc += bytes;
else
{
if (prdt_count >= m_max_hba_prdt_count)
break;
command_table.prdt_entry[prdt_count].dba = buffer_paddr & 0xFFFFFFFF;
command_table.prdt_entry[prdt_count].dbau = buffer_paddr >> 32;
command_table.prdt_entry[prdt_count].dbc = bytes - 1;
prdt_count++;
}
buffer = buffer.slice(bytes);
total_bytes += bytes;
extend_paddr = buffer_paddr + bytes;
}
if (const size_t rem = total_bytes % sector_size())
{
// TODO: this wont work with block sizes > PAGE_SIZE
ASSERT(rem < static_cast<size_t>(command_table.prdt_entry[prdt_count - 1].dbc + 1));
command_table.prdt_entry[prdt_count - 1].dbc -= rem;
total_bytes -= rem;
}
command_header.prdtl = prdt_count;
const size_t sector_count = total_bytes / sector_size();
volatile auto& fis_command = *reinterpret_cast<volatile FISRegisterH2D*>(&command_table.cfis[0]);
fis_command.fis_type = FIS_TYPE_REGISTER_H2D; fis_command.fis_type = FIS_TYPE_REGISTER_H2D;
fis_command.c = 1; fis_command.c = 1;
const bool needs_extended = lba >= (1 << 24) || sector_count > 0xFF; const bool needs_extended = (lba + sector_count) > (1 << 24) || sector_count > 0xFF;
ASSERT (!needs_extended || (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED)); ASSERT (!needs_extended || (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED));
switch (command) switch (command)
@@ -283,23 +371,70 @@ namespace Kernel
fis_command.count_lo = (sector_count >> 0) & 0xFF; fis_command.count_lo = (sector_count >> 0) & 0xFF;
fis_command.count_hi = (sector_count >> 8) & 0xFF; fis_command.count_hi = (sector_count >> 8) & 0xFF;
while (m_port->tfd & (ATA_STATUS_BSY | ATA_STATUS_DRQ)) TRY(send_command_and_wait(slot));
continue;
m_port->ci = 1 << slot.value(); return sector_count;
}
TRY(block_until_command_completed(slot.value())); BAN::ErrorOr<void> AHCIDevice::send_command_and_wait(uint32_t slot)
{
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + s_ata_timeout_ms;
SpinLockGuard _(m_command_lock);
m_port->ci |= 1u << slot;
while (m_port->ci & (1u << slot))
{
if (SystemTimer::get().ms_since_boot() >= timeout_ms)
{
m_free_slots |= 1u << slot;
return BAN::Error::from_errno(ETIMEDOUT);
}
BlockableSpinLock block(m_command_lock);
m_command_blocker.block_with_wake_time_ms(timeout_ms, &block);
}
m_free_slots |= 1u << slot;
constexpr uint32_t is_error =
(1 << 30) | // task file error
(1 << 29) | // host bus fatal error
(1 << 28) | // host bus data error
(1 << 27) | // interface fatal error
(1 << 26) | // interface non-fatal error
(1 << 24); // overflow
if (const uint32_t is = (m_prev_is.exchange(0) | m_port->is); is & is_error)
return BAN::Error::from_errno(EFAULT);
if (m_port->tfd & (ATA_STATUS_ERR | ATA_STATUS_DF))
return BAN::Error::from_errno(EFAULT);
return {}; return {};
} }
BAN::Optional<uint32_t> AHCIDevice::find_free_command_slot() BAN::ErrorOr<uint32_t> AHCIDevice::find_free_command_slot()
{ {
uint32_t slots = m_port->sact | m_port->ci; const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + s_ata_timeout_ms;
for (uint32_t i = 0; i < m_controller->command_slot_count(); i++)
if (!(slots & (1 << i))) SpinLockGuard _(m_command_lock);
return i;
return {}; for (;;)
{
if (const uint32_t usable_slots = ~(m_port->sact | m_port->ci) & m_free_slots)
{
const uint32_t slot = __builtin_ctz(usable_slots);
m_free_slots &= ~(1u << slot);
return slot;
}
if (SystemTimer::get().ms_since_boot() >= timeout_ms)
return BAN::Error::from_errno(ETIMEDOUT);
BlockableSpinLock block(m_command_lock);
m_command_blocker.block_with_timeout_ms(timeout_ms, &block);
}
} }
} }
+3 -3
View File
@@ -1,4 +1,4 @@
#include <kernel/Lock/SpinLockAsMutex.h> #include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Storage/NVMe/Queue.h> #include <kernel/Storage/NVMe/Queue.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
@@ -91,8 +91,8 @@ namespace Kernel
while (~m_used_mask == 0) while (~m_used_mask == 0)
{ {
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_lock);
m_thread_blocker.block_with_timeout_ms(s_nvme_command_timeout_ms, &smutex); m_thread_blocker.block_with_timeout_ms(s_nvme_command_timeout_ms, &block);
} }
uint16_t cid = 0; uint16_t cid = 0;
+7 -5
View File
@@ -79,17 +79,19 @@ namespace Kernel
if (!device) if (!device)
return BAN::Error::from_errno(ENODEV); return BAN::Error::from_errno(ENODEV);
if (offset % device->blksize() || buffer.size() % device->blksize()) if (offset < 0 || offset % device->blksize())
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(EINVAL);
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1; const uint64_t blocks_in_partition = m_last_block - m_first_block + 1;
uint32_t first_block = offset / device->blksize(); const uint64_t first_block = offset / device->blksize();
uint32_t block_count = buffer.size() / device->blksize(); uint64_t block_count = buffer.size() / device->blksize();
if (first_block >= blocks_in_partition) if (first_block >= blocks_in_partition)
return 0; return 0;
if (first_block + block_count > blocks_in_partition) if (first_block + block_count > blocks_in_partition)
block_count = blocks_in_partition - first_block; block_count = blocks_in_partition - first_block;
if (block_count == 0)
return 0;
TRY(read_blocks(first_block, block_count, buffer)); TRY(read_blocks(first_block, block_count, buffer));
return block_count * device->blksize(); return block_count * device->blksize();
+32 -10
View File
@@ -301,22 +301,44 @@ namespace Kernel
BAN::ErrorOr<size_t> StorageDevice::read_impl(off_t offset, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> StorageDevice::read_impl(off_t offset, BAN::ByteSpan buffer)
{ {
if (offset % sector_size()) if (offset < 0 || offset % sector_size())
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
if (buffer.size() % sector_size())
return BAN::Error::from_errno(EINVAL); const uint64_t total_blocks = total_size() / sector_size();
TRY(read_sectors(offset / sector_size(), buffer.size() / sector_size(), buffer));
return buffer.size(); const uint64_t first_block = offset / sector_size();
uint64_t block_count = buffer.size() / sector_size();
if (first_block >= total_blocks)
return 0;
if (first_block + block_count > total_blocks)
block_count = m_blocks - first_block;
if (block_count == 0)
return 0;
TRY(read_sectors(first_block, block_count, buffer));
return block_count * sector_size();
} }
BAN::ErrorOr<size_t> StorageDevice::write_impl(off_t offset, BAN::ConstByteSpan buffer) BAN::ErrorOr<size_t> StorageDevice::write_impl(off_t offset, BAN::ConstByteSpan buffer)
{ {
if (offset % sector_size()) if (offset < 0 || offset % sector_size())
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
if (buffer.size() % sector_size())
return BAN::Error::from_errno(EINVAL); const uint64_t total_blocks = total_size() / sector_size();
TRY(write_sectors(offset / sector_size(), buffer.size() / sector_size(), buffer));
return buffer.size(); const uint64_t first_block = offset / sector_size();
uint64_t block_count = buffer.size() / sector_size();
if (first_block >= total_blocks)
return 0;
if (first_block + block_count > total_blocks)
block_count = m_blocks - first_block;
if (block_count == 0)
return 0;
TRY(write_sectors(first_block, block_count, buffer));
return block_count * sector_size();
} }
} }
+3 -3
View File
@@ -1,6 +1,6 @@
#include <kernel/Device/DeviceNumbers.h> #include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Lock/SpinLockAsMutex.h> #include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Terminal/PseudoTerminal.h> #include <kernel/Terminal/PseudoTerminal.h>
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
@@ -112,8 +112,8 @@ namespace Kernel
while (m_buffer_size == 0) while (m_buffer_size == 0)
{ {
SpinLockGuardAsMutex smutex(guard); BlockableSpinLock block(m_buffer_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &smutex)); TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &block));
} }
const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer_size); const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer_size);
-1
View File
@@ -7,7 +7,6 @@
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Input/InputDevice.h> #include <kernel/Input/InputDevice.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Terminal/TTY.h> #include <kernel/Terminal/TTY.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
+1 -1
View File
@@ -761,7 +761,7 @@ namespace Kernel
thread_blocker.block_with_wake_time_ns(wake_time_ns, mutex); thread_blocker.block_with_wake_time_ns(wake_time_ns, mutex);
if (is_interrupted_by_signal(true)) if (is_interrupted_by_signal(true))
return BAN::Error::from_errno(EINTR); return BAN::Error::from_errno(EINTR);
if (etimedout && SystemTimer::get().ms_since_boot() >= wake_time_ns) if (etimedout && SystemTimer::get().ns_since_boot() >= wake_time_ns)
return BAN::Error::from_errno(ETIMEDOUT); return BAN::Error::from_errno(ETIMEDOUT);
return {}; return {};
} }
+1 -1
View File
@@ -230,7 +230,7 @@ static void init2(void*)
if (!cmdline.disable_acpi) if (!cmdline.disable_acpi)
{ {
if (auto ret = ACPI::ACPI::get().enter_acpi_mode(InterruptController::get().is_using_apic()); ret.is_error()) if (auto ret = ACPI::ACPI::get().enter_acpi_mode(); ret.is_error())
dprintln("Failed to enter ACPI mode: {}", ret.error()); dprintln("Failed to enter ACPI mode: {}", ret.error());
if (auto ret = ACPI::ACPI::get().initialize_acpi_devices(); ret.is_error()) if (auto ret = ACPI::ACPI::get().initialize_acpi_devices(); ret.is_error())
dwarnln("Could not initialize ACPI devices: {}", ret.error()); dwarnln("Could not initialize ACPI devices: {}", ret.error());
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash ../install.sh
NAME='ClassiCube'
VERSION='1.3.8'
DOWNLOAD_URL="https://github.com/ClassiCube/ClassiCube/archive/refs/tags/$VERSION.tar.gz#35293acf1e63baeca832dec2512283f2975c79ddf80cc855a12c10464723a6c4"
DEPENDENCIES=('SDL3' 'openal-soft' 'openssl' 'dejavu-fonts-ttf')
configure() {
make clean PLAT=banan-os
}
build() {
make -j$(nproc) banan-os RELEASE=1 || exit 1
}
install() {
mkdir -p "$DESTDIR/usr/bin"
cp -v 'ClassiCube' "$DESTDIR/usr/bin/" || exit 1
}
@@ -0,0 +1,148 @@
Binary files ClassiCube-1.3.8/ClassiCube and ClassiCube-1.3.8-banan_os/ClassiCube differ
diff -ruN ClassiCube-1.3.8/Makefile ClassiCube-1.3.8-banan_os/Makefile
--- ClassiCube-1.3.8/Makefile 2026-02-16 11:59:50.000000000 +0200
+++ ClassiCube-1.3.8-banan_os/Makefile 2026-07-11 00:04:53.761350011 +0300
@@ -163,6 +163,12 @@
BUILD_DIR = build/serenity
endif
+ifeq ($(PLAT),banan-os)
+ LDFLAGS = -g
+ LIBS = -lOSMesa -lSDL3
+ BUILD_DIR = build/banan-os
+endif
+
ifeq ($(PLAT),irix)
CC = gcc
LIBS = -lGL -lX11 -lXi -lpthread -ldl
@@ -247,6 +253,8 @@
$(MAKE) $(TARGET) PLAT=beos
serenityos:
$(MAKE) $(TARGET) PLAT=serenityos
+banan-os:
+ $(MAKE) $(TARGET) PLAT=banan-os
irix:
$(MAKE) $(TARGET) PLAT=irix
riscos:
diff -ruN ClassiCube-1.3.8/src/Core.h ClassiCube-1.3.8-banan_os/src/Core.h
--- ClassiCube-1.3.8/src/Core.h 2026-02-16 11:59:50.000000000 +0200
+++ ClassiCube-1.3.8-banan_os/src/Core.h 2026-07-11 00:04:53.775996187 +0300
@@ -254,6 +254,15 @@
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_SDL2
+#elif defined __banan_os__
+ #define CC_BUILD_BANAN
+ #define CC_BUILD_POSIX
+ #define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
+ #define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
+ #define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_OPENSSL
+ #define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL
+ #define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL2
+ #define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_SDL3
#elif defined MSDOS
#undef CC_BUILD_FREETYPE
#define CC_BUILD_MSDOS
diff -ruN ClassiCube-1.3.8/src/Logger.c ClassiCube-1.3.8-banan_os/src/Logger.c
--- ClassiCube-1.3.8/src/Logger.c 2026-02-16 11:59:50.000000000 +0200
+++ ClassiCube-1.3.8-banan_os/src/Logger.c 2026-07-11 00:04:53.778429266 +0300
@@ -27,7 +27,7 @@
static HANDLE curProcess = CUR_PROCESS_HANDLE;
static cc_uintptr spRegister;
-#elif defined CC_BUILD_OPENBSD || defined CC_BUILD_HAIKU || defined CC_BUILD_SERENITY
+#elif defined CC_BUILD_OPENBSD || defined CC_BUILD_HAIKU || defined CC_BUILD_SERENITY || defined CC_BUILD_BANAN
#include <signal.h>
/* These operating systems don't provide sys/ucontext.h */
/* But register constants be found from includes in <signal.h> */
@@ -445,6 +445,11 @@
String_AppendConst(trace, "-- backtrace unimplemented --");
/* TODO: Backtrace using LibSymbolication */
}
+#elif defined CC_BUILD_BANAN
+void Logger_Backtrace(cc_string* trace, void* ctx) {
+ String_AppendConst(trace, "-- backtrace unimplemented --");
+ /* TODO: Backtrace using LibSymbolication */
+}
#elif defined CC_BUILD_IRIX
void Logger_Backtrace(cc_string* trace, void* ctx) {
String_AppendConst(trace, "-- backtrace unimplemented --");
@@ -965,6 +970,19 @@
Dump_X64()
#else
#error "Unknown CPU architecture"
+#endif
+}
+#elif defined CC_BUILD_BANAN
+static void PrintRegisters(cc_string* str, void* ctx) {
+ mcontext_t* r = &((ucontext_t*)ctx)->uc_mcontext;
+#if defined __i386__
+ #define REG_GET(ign, reg) &r->gregs[REG_E##reg]
+ Dump_X86()
+#elif defined __x86_64__
+ #define REG_GET(ign, reg) &r->gregs[REG_R##reg]
+ Dump_X64()
+#else
+ #error "Unknown CPU architecture"
#endif
}
#elif defined CC_BUILD_IRIX
diff -ruN ClassiCube-1.3.8/src/Platform_Posix.c ClassiCube-1.3.8-banan_os/src/Platform_Posix.c
--- ClassiCube-1.3.8/src/Platform_Posix.c 2026-02-16 11:59:50.000000000 +0200
+++ ClassiCube-1.3.8-banan_os/src/Platform_Posix.c 2026-07-11 00:19:51.961830818 +0300
@@ -36,7 +36,11 @@
const cc_result ReturnCode_PathNotFound = 99999;
const cc_result ReturnCode_DirectoryExists = EEXIST;
const cc_result ReturnCode_SocketInProgess = EINPROGRESS;
+#ifdef CC_BUILD_BANAN
+const cc_result ReturnCode_SocketWouldBlock = EAGAIN;
+#else
const cc_result ReturnCode_SocketWouldBlock = EWOULDBLOCK;
+#endif
const cc_result ReturnCode_SocketDropped = EPIPE;
#define SUPPORTS_GETADDRINFO 1
@@ -633,6 +637,10 @@
static const cc_string dirs[] = {
String_FromConst("/res/fonts")
};
+#elif defined CC_BUILD_BANAN
+ static const cc_string dirs[] = {
+ String_FromConst("/usr/share/fonts")
+ };
#elif defined CC_BUILD_OS2
static const cc_string dirs[] = {
String_FromConst("/@unixroot/usr/share/fonts"),
@@ -1048,7 +1056,7 @@
*len = String_CalcLen(path, NATIVE_STR_LEN);
return 0;
}
-#elif defined CC_BUILD_LINUX || defined CC_BUILD_SERENITY
+#elif defined CC_BUILD_LINUX || defined CC_BUILD_SERENITY || defined CC_BUILD_BANAN
static cc_result Process_RawGetExePath(char* path, int* len) {
*len = readlink("/proc/self/exe", path, NATIVE_STR_LEN);
return *len == -1 ? errno : 0;
@@ -1649,6 +1657,23 @@
cc_result Platform_SetDefaultCurrentDirectory(int argc, char **argv) {
char path[NATIVE_STR_LEN];
+
+#ifdef CC_BUILD_BANAN
+ const char* home_env = getenv("HOME");
+ if (home_env != nullptr)
+ {
+ strcpy(path, home_env);
+
+ strcat(path, "/Games");
+ mkdir(path, 0755);
+
+ strcat(path, "/ClassiCube");
+ mkdir(path, 0755);
+
+ return chdir(path) == -1 ? errno : 0;
+ }
+#endif
+
int i, len = 0;
cc_result res;
if (!IsProblematicWorkingDirectory()) return 0;
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash ../install.sh
NAME='ccleste'
VERSION='1.4.0'
DOWNLOAD_URL="https://github.com/lemon32767/ccleste/archive/refs/tags/v$VERSION.tar.gz#32dfd797f3c863201e0c19aa97974c56a8ed589a34c0522503f25f6e1399edd6"
DEPENDENCIES=('sdl2-compat' 'SDL2_mixer')
configure() {
make clean
}
build() {
make SDL_PREFIX="$BANAN_SYSROOT/usr/bin/" || exit 1
}
install() {
mkdir -p "$DESTDIR/usr/bin" "$DESTDIR/usr/share/Games/ccleste"
cp -v ccleste "$DESTDIR/usr/bin/" || exit 1
cp -rv data/* "$DESTDIR/usr/share/Games/ccleste/" || exit 1
}
@@ -0,0 +1,29 @@
diff -ruN ccleste-1.4.0/Makefile ccleste-1.4.0-banan_os/Makefile
--- ccleste-1.4.0/Makefile 2021-11-24 16:25:50.000000000 +0200
+++ ccleste-1.4.0-banan_os/Makefile 2026-07-13 10:40:21.576609103 +0300
@@ -3,11 +3,11 @@
SDL_VER?=2
ifeq ($(SDL_VER),2)
- SDL_CONFIG=sdl2-config
+ SDL_CONFIG=$(SDL_PREFIX)sdl2-config
SDL_LD=-lSDL2 -lSDL2_mixer
else
ifeq ($(SDL_VER),1)
- SDL_CONFIG=sdl-config
+ SDL_CONFIG=$(SDL_PREFIX)sdl-config
SDL_LD=-lSDL -lSDL_mixer
else
SDL_CONFIG=$(error "invalid SDL version '$(SDL_VER)'. possible values are '1' and '2'")
diff -ruN ccleste-1.4.0/sdl12main.c ccleste-1.4.0-banan_os/sdl12main.c
--- ccleste-1.4.0/sdl12main.c 2021-11-24 16:25:50.000000000 +0200
+++ ccleste-1.4.0-banan_os/sdl12main.c 2026-07-13 10:39:55.050258303 +0300
@@ -83,6 +83,8 @@
static char* GetDataPath(char* path, int n, const char* fname) {
#ifdef _3DS
snprintf(path, n, "romfs:/%s", fname);
+#elif defined(__banan_os__)
+ snprintf(path, n, "/usr/share/Games/ccleste/%s", fname);
#else
#ifdef _WIN32
char pathsep = '\\';
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash ../install.sh
NAME='dejavu-fonts-ttf'
VERSION='2.37'
DOWNLOAD_URL="http://sourceforge.net/projects/dejavu/files/dejavu/$VERSION/dejavu-fonts-ttf-$VERSION.tar.bz2#fa9ca4d13871dd122f61258a80d01751d603b4d3ee14095d65453b4e846e17d7"
configure() {
:
}
build() {
:
}
install() {
mkdir -p "$DESTDIR/usr/share/fonts/TTF" || exit 1
cp -v ttf/* "$DESTDIR/usr/share/fonts/TTF/" || exit 1
mkdir -p "$DESTDIR/usr/share/fontconfig/conf.avail" || exit 1
cp -v "fontconfig/"* "$DESTDIR/usr/share/fontconfig/conf.avail/" || exit 1
}
+1 -21
View File
@@ -3,7 +3,7 @@
NAME='fontconfig' NAME='fontconfig'
VERSION='2.17.1' VERSION='2.17.1'
DOWNLOAD_URL="https://gitlab.freedesktop.org/fontconfig/fontconfig/-/archive/$VERSION/fontconfig-$VERSION.tar.gz#82e73b26adad651b236e5f5d4b3074daf8ff0910188808496326bd3449e5261d" DOWNLOAD_URL="https://gitlab.freedesktop.org/fontconfig/fontconfig/-/archive/$VERSION/fontconfig-$VERSION.tar.gz#82e73b26adad651b236e5f5d4b3074daf8ff0910188808496326bd3449e5261d"
DEPENDENCIES=('harfbuzz' 'freetype' 'expat' 'libiconv') DEPENDENCIES=('harfbuzz' 'freetype' 'expat' 'libiconv' 'dejavu-fonts-ttf')
CONFIGURE_OPTIONS=( CONFIGURE_OPTIONS=(
'-Dprefix=/usr' '-Dprefix=/usr'
'-Dbuildtype=release' '-Dbuildtype=release'
@@ -26,23 +26,3 @@ build() {
install() { install() {
meson install --destdir="$DESTDIR" -C build || exit 1 meson install --destdir="$DESTDIR" -C build || exit 1
} }
post_install() {
pushd .. &>/dev/null
local font_name='dejavu-fonts-ttf-2.37'
if [ ! -f "$font_name.tar.bz2" ]; then
wget "http://sourceforge.net/projects/dejavu/files/dejavu/2.37/$font_name.tar.bz2" || exit 1
fi
if [ ! -d "$font_name" ]; then
tar xf "$font_name.tar.bz2" || exit 1
fi
mkdir -p "$DESTDIR/usr/share/fonts/TTF" || exit 1
cp "$font_name/ttf/"* "$DESTDIR/usr/share/fonts/TTF/" || exit 1
cp "$font_name/fontconfig/"* "$DESTDIR/usr/share/fontconfig/conf.avail/" || exit 1
popd &>/dev/null
}
+2 -2
View File
@@ -1,8 +1,8 @@
#!/bin/bash ../install.sh #!/bin/bash ../install.sh
NAME='gcc' NAME='gcc'
VERSION='15.2.0' VERSION='15.3.0'
DOWNLOAD_URL="https://ftpmirror.gnu.org/gnu/gcc/gcc-$VERSION/gcc-$VERSION.tar.xz#438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e" DOWNLOAD_URL="https://ftpmirror.gnu.org/gnu/gcc/gcc-$VERSION/gcc-$VERSION.tar.xz#fa59c1beef8995f27c4d71c1df227587189315d3e6faff1bb4306e61b0c530eb"
DEPENDENCIES=('binutils' 'gmp' 'mpfr' 'mpc') DEPENDENCIES=('binutils' 'gmp' 'mpfr' 'mpc')
MAKE_INSTALL_TARGETS=('install-strip-gcc' 'install-strip-target-libgcc' 'install-strip-target-libstdc++-v3') MAKE_INSTALL_TARGETS=('install-strip-gcc' 'install-strip-target-libgcc' 'install-strip-target-libstdc++-v3')
CONFIGURE_OPTIONS=( CONFIGURE_OPTIONS=(
@@ -1,7 +1,7 @@
diff -ruN gcc-12.2.0/gcc/configure gcc-12.2.0-banan_os/gcc/configure diff -ruN gcc-15.3.0/gcc/configure gcc-15.3.0-banan_os/gcc/configure
--- gcc-12.2.0/gcc/configure 2022-08-19 11:09:52.736664469 +0300 --- gcc-15.3.0/gcc/configure 2026-06-12 09:09:06.318521299 +0300
+++ gcc-12.2.0-banan_os/gcc/configure 2024-08-08 09:30:58.730876253 +0300 +++ gcc-15.3.0-banan_os/gcc/configure 2026-07-09 22:14:04.081210055 +0300
@@ -9426,6 +9426,7 @@ @@ -9610,6 +9610,7 @@
fi fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
$as_echo_n "checking whether byte ordering is bigendian... " >&6; } $as_echo_n "checking whether byte ordering is bigendian... " >&6; }
-1
View File
@@ -1 +0,0 @@
../../../toolchain/gcc-15.2.0.patch
+1
View File
@@ -0,0 +1 @@
../../../toolchain/gcc-15.3.0.patch
+4 -7
View File
@@ -1,14 +1,11 @@
#!/bin/bash ../install.sh #!/bin/bash ../install.sh
NAME='lynx' NAME='lynx'
VERSION='2.9.2' VERSION='2.9.3'
DOWNLOAD_URL="https://invisible-island.net/archives/lynx/tarballs/lynx$VERSION.tar.gz#99f8f28f860094c533100d1cedf058c27fb242ce25e991e2d5f30ece4457a3bf" DOWNLOAD_URL="https://invisible-island.net/archives/lynx/tarballs/lynx$VERSION.tar.gz#6e99e46980974a6d89eceefbb26ca8c7aa7702b78ecb5bad383b859af225d052"
TAR_CONTENT="lynx$VERSION" TAR_CONTENT="lynx$VERSION"
DEPENDENCIES=('ncurses' 'openssl' 'zlib') DEPENDENCIES=('ncurses' 'openssl' 'libiconv' 'bzip2' 'zlib' 'zstd')
CONFIG_SUB=('config.sub')
CONFIGURE_OPTIONS=( CONFIGURE_OPTIONS=(
'--without-system-type' '--with-screen=ncurses'
'--with-sceen=ncurses'
'--with-ssl' '--with-ssl'
'--with-zlib'
) )
@@ -0,0 +1,12 @@
diff -ruN lynx-2.9.3/src/LYUtils.c lynx-2.9.3-banan_os/src/LYUtils.c
--- lynx-2.9.3/src/LYUtils.c 2026-05-25 03:27:54.000000000 +0300
+++ lynx-2.9.3-banan_os/src/LYUtils.c 2026-07-09 02:54:54.881373038 +0300
@@ -42,7 +42,7 @@
#if !defined(kbhit) && defined(_WCONIO_DEFINED)
#define kbhit() _kbhit() /* reasonably recent conio.h */
#endif
-#elif defined(__minix)
+#elif defined(__minix) || defined(__banan_os__)
#include <termios.h> /* for struct winsize */
#endif /* __MINGW32__ */
+7 -2
View File
@@ -9,15 +9,20 @@ CONFIGURE_OPTIONS=(
"--with-pkg-config-libdir=/usr/lib/pkgconfig" "--with-pkg-config-libdir=/usr/lib/pkgconfig"
'--enable-pc-files' '--enable-pc-files'
'--enable-sigwinch' '--enable-sigwinch'
'--disable-widec'
'--with-shared' '--with-shared'
'--with-trace' '--without-tests'
'--without-ada' '--without-ada'
'--without-manpages' '--without-manpages'
CFLAGS='-std=c17' CFLAGS='-std=c17'
) )
post_install() { post_install() {
for lib in ncurses ncurses++ form panel menu; do
ln -sv ${lib}w.pc "$DESTDIR/usr/lib/pkgconfig/$lib.pc"
done
ln -sv libncursesw.so "$DESTDIR/usr/lib/libncurses.so"
shellrc="$BANAN_SYSROOT/home/user/.shellrc" shellrc="$BANAN_SYSROOT/home/user/.shellrc"
grep -q 'export NCURSES_NO_UTF8_ACS=' "$shellrc" || echo 'export NCURSES_NO_UTF8_ACS=1' >> "$shellrc" grep -q 'export NCURSES_NO_UTF8_ACS=' "$shellrc" || echo 'export NCURSES_NO_UTF8_ACS=1' >> "$shellrc"
} }
+7 -5
View File
@@ -10,8 +10,13 @@ configure() {
} }
build() { build() {
baseq2_tar=../baseq2.tar.gz local cflags='-Dstricmp=strcasecmp -O2 -ffast-math -Wno-incompatible-pointer-types -Wno-pointer-to-int-cast'
baseq2_hash=9660c306d9440ff7d534f165ae4a7f550b9e879d5190830953034ebda10e873a make -j$(nproc) createdirs build/quake2-soft CC="$CC" CFLAGS="$cflags" SDL_PREFIX="$BANAN_SYSROOT/usr/bin/" || exit 1
}
pre_install() {
local baseq2_tar='../baseq2.tar.gz'
local baseq2_hash='9660c306d9440ff7d534f165ae4a7f550b9e879d5190830953034ebda10e873a'
if [ -f $baseq2_tar ]; then if [ -f $baseq2_tar ]; then
if ! echo "$baseq2_hash $baseq2_tar" | sha256sum --check >/dev/null; then if ! echo "$baseq2_hash $baseq2_tar" | sha256sum --check >/dev/null; then
@@ -25,9 +30,6 @@ build() {
echo "File hash does not match" >&2 echo "File hash does not match" >&2
exit 1 exit 1
fi fi
cflags='-Dstricmp=strcasecmp -O3 -ffast-math -Wno-incompatible-pointer-types -Wno-pointer-to-int-cast'
make CC="$CC" CFLAGS="$cflags" SDL_PATH="$BANAN_SYSROOT/usr/bin/" -j$(nproc) createdirs build/quake2-soft || exit 1
} }
install() { install() {
@@ -1,52 +0,0 @@
From fd08d90bb7ee8388a9e005bae23edcccbfc73dbb Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <[email protected]>
Date: Sun, 10 Aug 2025 19:52:20 +0300
Subject: [PATCH] add support for custom SDL path and add sound support
---
Makefile | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
index 8edbffa..de2f605 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
-SDL_CFLAGS = `sdl2-config --cflags`
-SDL_LIBS = `sdl2-config --cflags --libs` -lSDL2_mixer
+SDL_CFLAGS = `$(SDL_PATH)sdl2-config --cflags`
+SDL_LIBS = `$(SDL_PATH)sdl2-config --cflags --libs` -lSDL2_mixer
MOUNT_DIR=.
@@ -124,7 +124,7 @@ QUAKE2_OBJS = \
\
$(BUILDDIR)/net/net_unix.o \
\
- $(BUILDDIR)/sound/snddma_null.o \
+ $(BUILDDIR)/sound/snd_sdl.o \
\
$(BUILDDIR)/port_platform_unix.o
@@ -353,7 +353,7 @@ $(BUILDDIR)/client/vid_menu.o : $(OTHER_DIR)/vid_menu.c
$(BUILDDIR)/client/vid_lib.o : $(OTHER_DIR)/vid_lib.c
$(DO_CC)
-$(BUILDDIR)/client/snddma_null.o : $(NULL_DIR)/snddma_null.c
+$(BUILDDIR)/client/snd_sdl.o : $(NULL_DIR)/snd_sdl.c
$(DO_CC)
$(BUILDDIR)/client/q_system.o : $(OTHER_DIR)/q_system.c
@@ -368,7 +368,7 @@ $(BUILDDIR)/net/net_unix.o : $(NET_DIR)/net_unix.c
$(BUILDDIR)/port_platform_unix.o : $(MOUNT_DIR)/port_platform_unix.c
$(DO_CC)
-$(BUILDDIR)/sound/snddma_null.o : $(SOUND_DIR)/snddma_null.c
+$(BUILDDIR)/sound/snd_sdl.o : $(SOUND_DIR)/snd_sdl.c
$(DO_GL_SHLIB_CC)
--
2.50.1
@@ -0,0 +1,66 @@
From e93c43f5c55e67cd3fb79bc890d698492cb5861d Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <[email protected]>
Date: Mon, 13 Jul 2026 23:05:59 +0300
Subject: [PATCH] cleanup-makefile-for-cross-compile
---
Makefile | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile
index 8edbffa..88709bd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
-SDL_CFLAGS = `sdl2-config --cflags`
-SDL_LIBS = `sdl2-config --cflags --libs` -lSDL2_mixer
+SDL_CFLAGS = `$(SDL_PREFIX)sdl2-config --cflags`
+SDL_LIBS = `$(SDL_PREFIX)sdl2-config --cflags --libs` -lSDL2_mixer
MOUNT_DIR=.
@@ -28,10 +28,9 @@ RELEASE_CFLAGS=$(BASE_CFLAGS) -O6 -ffast-math -funroll-loops \
DEBUG_CFLAGS=$(BASE_CFLAGS) -g
LDFLAGS=-ldl -lm
-XCFLAGS=-I/opt/X11/include
+XCFLAGS=
-GLLDFLAGS=-L/usr/X11/lib -L/usr/local/lib \
- $(SDL_LIBS) -lGL
+GLLDFLAGS=$(SDL_LIBS) -lGL
GLCFLAGS=$(SDL_CFLAGS)
SHLIBEXT=so
@@ -124,7 +123,7 @@ QUAKE2_OBJS = \
\
$(BUILDDIR)/net/net_unix.o \
\
- $(BUILDDIR)/sound/snddma_null.o \
+ $(BUILDDIR)/sound/snd_sdl.o \
\
$(BUILDDIR)/port_platform_unix.o
@@ -227,7 +226,7 @@ REF_GL_OBJS = \
$(BUILDDIR)/quake2-soft : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(REF_SOFT_SDL_OBJS)
- $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(REF_SOFT_SDL_OBJS) $(LDFLAGS) $(GLLDFLAGS)
+ $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(REF_SOFT_SDL_OBJS) $(LDFLAGS) $(SDL_LIBS)
$(BUILDDIR)/quake2-gl : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_GL_OBJS)
$(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_GL_OBJS) $(LDFLAGS) $(GLLDFLAGS)
@@ -368,6 +367,9 @@ $(BUILDDIR)/net/net_unix.o : $(NET_DIR)/net_unix.c
$(BUILDDIR)/port_platform_unix.o : $(MOUNT_DIR)/port_platform_unix.c
$(DO_CC)
+$(BUILDDIR)/sound/snd_sdl.o : $(SOUND_DIR)/snd_sdl.c
+ $(DO_GL_SHLIB_CC)
+
$(BUILDDIR)/sound/snddma_null.o : $(SOUND_DIR)/snddma_null.c
$(DO_GL_SHLIB_CC)
--
2.55.0
@@ -1,42 +0,0 @@
From fbdf3e7c40c1de83a2361bb904d8dbd3464ccebd Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <[email protected]>
Date: Sun, 10 Aug 2025 19:54:38 +0300
Subject: [PATCH 2/2] fix socket creation
---
net/net_unix.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/net/net_unix.c b/net/net_unix.c
index a92e57c..f297dff 100644
--- a/net/net_unix.c
+++ b/net/net_unix.c
@@ -451,24 +451,16 @@ int NET_Socket (char *net_interface, int port)
qboolean _true = true;
int i = 1;
- if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ if ((newsocket = socket (PF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) == -1)
{
Com_Printf ("ERROR: UDP_OpenSocket: socket:", NET_ErrorString());
return 0;
}
- // make it non-blocking
- if (ioctl (newsocket, FIONBIO, &_true) == -1)
- {
- Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
- return 0;
- }
-
// make it broadcast capable
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
{
Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
- return 0;
}
if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
--
2.50.1
+1 -1
View File
@@ -5,7 +5,7 @@ BINUTILS_VERSION="binutils-2.45"
BINUTILS_TAR="$BINUTILS_VERSION.tar.xz" BINUTILS_TAR="$BINUTILS_VERSION.tar.xz"
BINUTILS_URL="https://ftpmirror.gnu.org/gnu/binutils/$BINUTILS_TAR" BINUTILS_URL="https://ftpmirror.gnu.org/gnu/binutils/$BINUTILS_TAR"
GCC_VERSION="gcc-15.2.0" GCC_VERSION="gcc-15.3.0"
GCC_TAR="$GCC_VERSION.tar.xz" GCC_TAR="$GCC_VERSION.tar.xz"
GCC_URL="https://ftpmirror.gnu.org/gnu/gcc/$GCC_VERSION/$GCC_TAR" GCC_URL="https://ftpmirror.gnu.org/gnu/gcc/$GCC_VERSION/$GCC_TAR"
@@ -1,6 +1,6 @@
diff -ruN gcc-15.2.0/config.sub gcc-15.2.0-banan_os/config.sub diff -ruN gcc-15.3.0/config.sub gcc-15.3.0-banan_os/config.sub
--- gcc-15.2.0/config.sub 2025-08-25 18:08:25.524209333 +0300 --- gcc-15.3.0/config.sub 2026-06-12 09:09:05.607510293 +0300
+++ gcc-15.2.0-banan_os/config.sub 2025-08-25 18:09:09.160072736 +0300 +++ gcc-15.3.0-banan_os/config.sub 2026-07-09 21:47:07.527710452 +0300
@@ -1749,7 +1749,7 @@ @@ -1749,7 +1749,7 @@
| onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
| midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
@@ -10,9 +10,9 @@ diff -ruN gcc-15.2.0/config.sub gcc-15.2.0-banan_os/config.sub
;; ;;
# This one is extra strict with allowed versions # This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*) sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
diff -ruN gcc-15.2.0/fixincludes/mkfixinc.sh gcc-15.2.0-banan_os/fixincludes/mkfixinc.sh diff -ruN gcc-15.3.0/fixincludes/mkfixinc.sh gcc-15.3.0-banan_os/fixincludes/mkfixinc.sh
--- gcc-15.2.0/fixincludes/mkfixinc.sh 2025-08-25 18:08:42.043663414 +0300 --- gcc-15.3.0/fixincludes/mkfixinc.sh 2026-06-12 09:09:05.644510866 +0300
+++ gcc-15.2.0-banan_os/fixincludes/mkfixinc.sh 2025-08-25 18:09:09.191771254 +0300 +++ gcc-15.3.0-banan_os/fixincludes/mkfixinc.sh 2026-07-09 21:47:07.527995337 +0300
@@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
# Check for special fix rules for particular targets # Check for special fix rules for particular targets
@@ -21,9 +21,9 @@ diff -ruN gcc-15.2.0/fixincludes/mkfixinc.sh gcc-15.2.0-banan_os/fixincludes/mkf
i?86-*-cygwin* | \ i?86-*-cygwin* | \
*-mingw32* | \ *-mingw32* | \
powerpc-*-eabisim* | \ powerpc-*-eabisim* | \
diff -ruN gcc-15.2.0/gcc/config/banan_os.h gcc-15.2.0-banan_os/gcc/config/banan_os.h diff -ruN gcc-15.3.0/gcc/config/banan_os.h gcc-15.3.0-banan_os/gcc/config/banan_os.h
--- gcc-15.2.0/gcc/config/banan_os.h 1970-01-01 02:00:00.000000000 +0200 --- gcc-15.3.0/gcc/config/banan_os.h 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.2.0-banan_os/gcc/config/banan_os.h 2025-08-25 18:09:09.192159227 +0300 +++ gcc-15.3.0-banan_os/gcc/config/banan_os.h 2026-07-09 21:47:07.528236221 +0300
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
+/* Useful if you wish to make target-specific GCC changes. */ +/* Useful if you wish to make target-specific GCC changes. */
+#undef TARGET_BANAN_OS +#undef TARGET_BANAN_OS
@@ -60,9 +60,9 @@ diff -ruN gcc-15.2.0/gcc/config/banan_os.h gcc-15.2.0-banan_os/gcc/config/banan_
+ builtin_assert ("system=unix"); \ + builtin_assert ("system=unix"); \
+ builtin_assert ("system=posix"); \ + builtin_assert ("system=posix"); \
+ } while(0); + } while(0);
diff -ruN gcc-15.2.0/gcc/config/banan_os.opt gcc-15.2.0-banan_os/gcc/config/banan_os.opt diff -ruN gcc-15.3.0/gcc/config/banan_os.opt gcc-15.3.0-banan_os/gcc/config/banan_os.opt
--- gcc-15.2.0/gcc/config/banan_os.opt 1970-01-01 02:00:00.000000000 +0200 --- gcc-15.3.0/gcc/config/banan_os.opt 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.2.0-banan_os/gcc/config/banan_os.opt 2025-08-25 18:09:09.192299819 +0300 +++ gcc-15.3.0-banan_os/gcc/config/banan_os.opt 2026-07-09 21:47:07.528330648 +0300
@@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
+; banan_os options. +; banan_os options.
+ +
@@ -96,14 +96,14 @@ diff -ruN gcc-15.2.0/gcc/config/banan_os.opt gcc-15.2.0-banan_os/gcc/config/bana
+Driver +Driver
+ +
+; This comment is to ensure we retain the blank line above. +; This comment is to ensure we retain the blank line above.
diff -ruN gcc-15.2.0/gcc/config/banan_os.opt.urls gcc-15.2.0-banan_os/gcc/config/banan_os.opt.urls diff -ruN gcc-15.3.0/gcc/config/banan_os.opt.urls gcc-15.3.0-banan_os/gcc/config/banan_os.opt.urls
--- gcc-15.2.0/gcc/config/banan_os.opt.urls 1970-01-01 02:00:00.000000000 +0200 --- gcc-15.3.0/gcc/config/banan_os.opt.urls 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.2.0-banan_os/gcc/config/banan_os.opt.urls 2025-08-25 18:09:09.192460665 +0300 +++ gcc-15.3.0-banan_os/gcc/config/banan_os.opt.urls 2026-07-09 21:47:07.528429404 +0300
@@ -0,0 +1 @@ @@ -0,0 +1 @@
+; Not sure what to put here but this works +; Not sure what to put here but this works
diff -ruN gcc-15.2.0/gcc/config.gcc gcc-15.2.0-banan_os/gcc/config.gcc diff -ruN gcc-15.3.0/gcc/config.gcc gcc-15.3.0-banan_os/gcc/config.gcc
--- gcc-15.2.0/gcc/config.gcc 2025-08-25 18:08:36.953184232 +0300 --- gcc-15.3.0/gcc/config.gcc 2026-06-12 09:09:06.107518032 +0300
+++ gcc-15.2.0-banan_os/gcc/config.gcc 2025-08-25 18:09:09.193116622 +0300 +++ gcc-15.3.0-banan_os/gcc/config.gcc 2026-07-09 21:47:07.528829877 +0300
@@ -723,6 +723,14 @@ @@ -723,6 +723,14 @@
# Common parts for widely ported systems. # Common parts for widely ported systems.
@@ -132,9 +132,9 @@ diff -ruN gcc-15.2.0/gcc/config.gcc gcc-15.2.0-banan_os/gcc/config.gcc
i[34567]86-*-dragonfly*) i[34567]86-*-dragonfly*)
tm_file="${tm_file} i386/unix.h i386/att.h elfos.h dragonfly.h dragonfly-stdint.h i386/dragonfly.h" tm_file="${tm_file} i386/unix.h i386/att.h elfos.h dragonfly.h dragonfly-stdint.h i386/dragonfly.h"
tmake_file="${tmake_file} i386/t-crtstuff" tmake_file="${tmake_file} i386/t-crtstuff"
diff -ruN gcc-15.2.0/libgcc/config/t-slibgcc gcc-15.2.0-banan_os/libgcc/config/t-slibgcc diff -ruN gcc-15.3.0/libgcc/config/t-slibgcc gcc-15.3.0-banan_os/libgcc/config/t-slibgcc
--- gcc-15.2.0/libgcc/config/t-slibgcc 2025-08-25 18:08:42.538268318 +0300 --- gcc-15.3.0/libgcc/config/t-slibgcc 2026-06-12 09:09:10.055579142 +0300
+++ gcc-15.2.0-banan_os/libgcc/config/t-slibgcc 2025-08-25 18:09:09.206796796 +0300 +++ gcc-15.3.0-banan_os/libgcc/config/t-slibgcc 2026-07-09 21:47:07.529617134 +0300
@@ -26,7 +26,6 @@ @@ -26,7 +26,6 @@
SHLIB_OBJS = @shlib_objs@ SHLIB_OBJS = @shlib_objs@
SHLIB_DIR = @multilib_dir@ SHLIB_DIR = @multilib_dir@
@@ -143,9 +143,9 @@ diff -ruN gcc-15.2.0/libgcc/config/t-slibgcc gcc-15.2.0-banan_os/libgcc/config/t
SHLIB_MAKE_SOLINK = $(LN_S) $(SHLIB_SONAME) $(SHLIB_DIR)/$(SHLIB_SOLINK) SHLIB_MAKE_SOLINK = $(LN_S) $(SHLIB_SONAME) $(SHLIB_DIR)/$(SHLIB_SOLINK)
SHLIB_INSTALL_SOLINK = $(LN_S) $(SHLIB_SONAME) \ SHLIB_INSTALL_SOLINK = $(LN_S) $(SHLIB_SONAME) \
$(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK) $(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK)
diff -ruN gcc-15.2.0/libgcc/config.host gcc-15.2.0-banan_os/libgcc/config.host diff -ruN gcc-15.3.0/libgcc/config.host gcc-15.3.0-banan_os/libgcc/config.host
--- gcc-15.2.0/libgcc/config.host 2025-08-25 18:08:42.103193239 +0300 --- gcc-15.3.0/libgcc/config.host 2026-06-12 09:09:09.987578090 +0300
+++ gcc-15.2.0-banan_os/libgcc/config.host 2025-08-25 18:09:09.221444143 +0300 +++ gcc-15.3.0-banan_os/libgcc/config.host 2026-07-09 21:47:07.529840209 +0300
@@ -627,6 +627,14 @@ @@ -627,6 +627,14 @@
fixed_point=no fixed_point=no
fi fi
@@ -161,9 +161,9 @@ diff -ruN gcc-15.2.0/libgcc/config.host gcc-15.2.0-banan_os/libgcc/config.host
bfin*-elf*) bfin*-elf*)
tmake_file="bfin/t-bfin bfin/t-crtlibid bfin/t-crtstuff t-libgcc-pic t-fdpbit" tmake_file="bfin/t-bfin bfin/t-crtlibid bfin/t-crtstuff t-libgcc-pic t-fdpbit"
extra_parts="$extra_parts crtbeginS.o crtendS.o crti.o crtn.o crtlibid.o" extra_parts="$extra_parts crtbeginS.o crtendS.o crti.o crtn.o crtlibid.o"
diff -ruN gcc-15.2.0/libstdc++-v3/acinclude.m4 gcc-15.2.0-banan_os/libstdc++-v3/acinclude.m4 diff -ruN gcc-15.3.0/libstdc++-v3/acinclude.m4 gcc-15.3.0-banan_os/libstdc++-v3/acinclude.m4
--- gcc-15.2.0/libstdc++-v3/acinclude.m4 2025-08-25 18:08:44.358147732 +0300 --- gcc-15.3.0/libstdc++-v3/acinclude.m4 2026-06-12 09:09:10.698589095 +0300
+++ gcc-15.2.0-banan_os/libstdc++-v3/acinclude.m4 2025-08-25 18:09:09.241116556 +0300 +++ gcc-15.3.0-banan_os/libstdc++-v3/acinclude.m4 2026-07-09 21:47:07.530425483 +0300
@@ -1792,7 +1792,7 @@ @@ -1792,7 +1792,7 @@
ac_has_nanosleep=yes ac_has_nanosleep=yes
ac_has_sched_yield=yes ac_has_sched_yield=yes
@@ -173,9 +173,9 @@ diff -ruN gcc-15.2.0/libstdc++-v3/acinclude.m4 gcc-15.2.0-banan_os/libstdc++-v3/
ac_has_clock_monotonic=yes ac_has_clock_monotonic=yes
ac_has_clock_realtime=yes ac_has_clock_realtime=yes
ac_has_nanosleep=yes ac_has_nanosleep=yes
diff -ruN gcc-15.2.0/libstdc++-v3/configure gcc-15.2.0-banan_os/libstdc++-v3/configure diff -ruN gcc-15.3.0/libstdc++-v3/configure gcc-15.3.0-banan_os/libstdc++-v3/configure
--- gcc-15.2.0/libstdc++-v3/configure 2025-08-25 18:08:47.550144038 +0300 --- gcc-15.3.0/libstdc++-v3/configure 2026-06-12 09:09:10.726589529 +0300
+++ gcc-15.2.0-banan_os/libstdc++-v3/configure 2025-08-25 18:09:09.262116528 +0300 +++ gcc-15.3.0-banan_os/libstdc++-v3/configure 2026-07-09 21:47:07.538829690 +0300
@@ -15784,8 +15784,8 @@ @@ -15784,8 +15784,8 @@
glibcxx_compiler_shared_flag="-D_GLIBCXX_SHARED" glibcxx_compiler_shared_flag="-D_GLIBCXX_SHARED"
@@ -196,7 +196,7 @@ diff -ruN gcc-15.2.0/libstdc++-v3/configure gcc-15.2.0-banan_os/libstdc++-v3/con
ac_has_clock_monotonic=yes ac_has_clock_monotonic=yes
ac_has_clock_realtime=yes ac_has_clock_realtime=yes
ac_has_nanosleep=yes ac_has_nanosleep=yes
@@ -28654,7 +28654,7 @@ @@ -28676,7 +28676,7 @@
# This is a freestanding configuration; there is nothing to do here. # This is a freestanding configuration; there is nothing to do here.
;; ;;
@@ -205,9 +205,9 @@ diff -ruN gcc-15.2.0/libstdc++-v3/configure gcc-15.2.0-banan_os/libstdc++-v3/con
$as_echo "#define HAVE_ACOSF 1" >>confdefs.h $as_echo "#define HAVE_ACOSF 1" >>confdefs.h
$as_echo "#define HAVE_ASINF 1" >>confdefs.h $as_echo "#define HAVE_ASINF 1" >>confdefs.h
diff -ruN gcc-15.2.0/libstdc++-v3/crossconfig.m4 gcc-15.2.0-banan_os/libstdc++-v3/crossconfig.m4 diff -ruN gcc-15.3.0/libstdc++-v3/crossconfig.m4 gcc-15.3.0-banan_os/libstdc++-v3/crossconfig.m4
--- gcc-15.2.0/libstdc++-v3/crossconfig.m4 2025-08-25 18:08:47.570807934 +0300 --- gcc-15.3.0/libstdc++-v3/crossconfig.m4 2026-06-12 09:09:10.727589544 +0300
+++ gcc-15.2.0-banan_os/libstdc++-v3/crossconfig.m4 2025-08-25 18:09:09.263116526 +0300 +++ gcc-15.3.0-banan_os/libstdc++-v3/crossconfig.m4 2026-07-09 21:47:07.540758931 +0300
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
# This is a freestanding configuration; there is nothing to do here. # This is a freestanding configuration; there is nothing to do here.
;; ;;
+1
View File
@@ -32,6 +32,7 @@ set(LIBC_SOURCES
regex.cpp regex.cpp
scanf_impl.cpp scanf_impl.cpp
sched.cpp sched.cpp
search.cpp
semaphore.cpp semaphore.cpp
setjmp.cpp setjmp.cpp
signal.cpp signal.cpp
@@ -7,10 +7,13 @@
__BEGIN_DECLS __BEGIN_DECLS
#ifndef __locale_t_defined typedef enum { __ENC_ASCII, __ENC_UTF8 } __encoding_e;
#define __locale_t_defined 1 struct __locale_t
typedef enum { LOCALE_INVALID, LOCALE_POSIX, LOCALE_UTF8 } locale_t; {
#endif const char* name;
__encoding_e encoding;
};
typedef struct __locale_t* locale_t;
__END_DECLS __END_DECLS
@@ -13,7 +13,7 @@ __BEGIN_DECLS
#include <stdint.h> #include <stdint.h>
typedef int pthread_once_t; typedef uint32_t pthread_once_t;
typedef pthread_t pthread_spinlock_t; typedef pthread_t pthread_spinlock_t;
@@ -0,0 +1,20 @@
#ifndef _BITS_TYPES_WINSIZE_H
#define _BITS_TYPES_WINSIZE_H 1
// https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/termios.h.html
#include <sys/cdefs.h>
__BEGIN_DECLS
struct winsize
{
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel; /* unused by kernel */
unsigned short ws_ypixel; /* unused by kernel */
};
__END_DECLS
#endif
+13 -5
View File
@@ -1,7 +1,7 @@
#ifndef _SEARCH_H #ifndef _SEARCH_H
#define _SEARCH_H 1 #define _SEARCH_H 1
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/search.h.html // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/search.h.html
#include <sys/cdefs.h> #include <sys/cdefs.h>
@@ -19,6 +19,14 @@ typedef struct
typedef enum { FIND, ENTER } ACTION; typedef enum { FIND, ENTER } ACTION;
typedef enum { preorder, postorder, endorder, leaf } VISIT; typedef enum { preorder, postorder, endorder, leaf } VISIT;
// NOTE: POSIX requires posix_tnode to be void but
// defining an internal type avoids casting
#ifdef __is_libc
typedef struct __posix_tnode posix_tnode;
#else
typedef void posix_tnode;
#endif
int hcreate(size_t nel); int hcreate(size_t nel);
void hdestroy(void); void hdestroy(void);
ENTRY* hsearch(ENTRY item, ACTION action); ENTRY* hsearch(ENTRY item, ACTION action);
@@ -26,10 +34,10 @@ void insque(void* element, void* pred);
void* lfind(const void* key, const void* base, size_t* nelp, size_t width, int (*compar)(const void*, const void*)); void* lfind(const void* key, const void* base, size_t* nelp, size_t width, int (*compar)(const void*, const void*));
void* lsearch(const void* key, void* base, size_t* nelp, size_t width, int (*compar)(const void*, const void*)); void* lsearch(const void* key, void* base, size_t* nelp, size_t width, int (*compar)(const void*, const void*));
void remque(void* element); void remque(void* element);
void* tdelete(const void* __restrict key, void** __restrict rootp, int(*compar)(const void*, const void*)); void* tdelete(const void* __restrict key, posix_tnode** __restrict rootp, int (*compar)(const void*, const void*));
void* tfind(const void* key, void* const* rootp, int(*compar)(const void*, const void*)); posix_tnode* tfind(const void* key, posix_tnode* const* rootp, int (*compar)(const void*, const void*));
void* tsearch(const void* key, void** rootp, int(*compar)(const void*, const void*)); posix_tnode* tsearch(const void* key, posix_tnode** rootp, int (*compar)(const void*, const void*));
void twalk(const void* root, void (*action)(const void*, VISIT, int)); void twalk(const posix_tnode* root, void (*action)(const posix_tnode*, VISIT, int));
__END_DECLS __END_DECLS
@@ -7,6 +7,8 @@ __BEGIN_DECLS
#include <stdint.h> #include <stdint.h>
#include <bits/types/winsize.h>
#define I_ATMARK 1 #define I_ATMARK 1
#define I_CANPUT 2 #define I_CANPUT 2
#define I_CKBAND 3 #define I_CKBAND 3
+2 -8
View File
@@ -10,6 +10,8 @@ __BEGIN_DECLS
#define __need_pid_t #define __need_pid_t
#include <sys/types.h> #include <sys/types.h>
#include <bits/types/winsize.h>
typedef unsigned int cc_t; typedef unsigned int cc_t;
typedef unsigned int speed_t; typedef unsigned int speed_t;
typedef unsigned int tcflag_t; typedef unsigned int tcflag_t;
@@ -39,14 +41,6 @@ struct termios
speed_t c_ispeed; speed_t c_ispeed;
}; };
struct winsize
{
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel; /* unused by kernel */
unsigned short ws_ypixel; /* unused by kernel */
};
#define BRKINT 0x001 #define BRKINT 0x001
#define ICRNL 0x002 #define ICRNL 0x002
#define IGNBRK 0x004 #define IGNBRK 0x004
+3 -4
View File
@@ -8,11 +8,10 @@ static const char* nl_langinfo_impl(nl_item item)
// only codeset is affected by current locales // only codeset is affected by current locales
if (item == CODESET) if (item == CODESET)
{ {
switch (__getlocale(LC_CTYPE)) switch (__getlocale(LC_CTYPE)->encoding)
{ {
case LOCALE_INVALID: ASSERT_NOT_REACHED(); case __ENC_ASCII: return "ANSI_X3.4-1968";
case LOCALE_UTF8: return "UTF-8"; case __ENC_UTF8: return "UTF-8";
case LOCALE_POSIX: return "ANSI_X3.4-1968";
} }
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
+56 -29
View File
@@ -5,35 +5,37 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
static __locale_t s_locale_posix {
.name = "C",
.encoding = __ENC_ASCII,
};
static __locale_t s_locale_utf8 {
.name = "C.UTF-8",
.encoding = __ENC_UTF8,
};
static locale_t s_current_locales[LC_ALL] { static locale_t s_current_locales[LC_ALL] {
LOCALE_POSIX, &s_locale_posix,
LOCALE_POSIX, &s_locale_posix,
LOCALE_POSIX, &s_locale_posix,
LOCALE_POSIX, &s_locale_posix,
LOCALE_POSIX, &s_locale_posix,
LOCALE_POSIX, &s_locale_posix,
}; };
static_assert(LC_ALL == 6); static_assert(LC_ALL == 6);
static locale_t str_to_locale(const char* locale) static locale_t str_to_locale(const char* locale)
{ {
if (*locale == '\0') if (*locale == '\0')
return LOCALE_UTF8; return &s_locale_utf8;
if (strcmp(locale, "C") == 0 || strcmp(locale, "POSIX") == 0)
return &s_locale_posix;
if (strcmp(locale, "C") == 0 || strcmp(locale, "LOCALE_POSIX") == 0)
return LOCALE_POSIX;
if (strcmp(locale, "C.UTF-8") == 0) if (strcmp(locale, "C.UTF-8") == 0)
return LOCALE_UTF8; return &s_locale_utf8;
return LOCALE_INVALID;
}
static const char* locale_to_str(locale_t locale) return nullptr;
{
if (locale == LOCALE_POSIX)
return "C";
if (locale == LOCALE_UTF8)
return "C.UTF-8";
ASSERT_NOT_REACHED();
} }
struct lconv* localeconv(void) struct lconv* localeconv(void)
@@ -80,17 +82,18 @@ char* setlocale(int category, const char* locale_str)
case LC_MONETARY: case LC_MONETARY:
case LC_NUMERIC: case LC_NUMERIC:
case LC_TIME: case LC_TIME:
strcpy(s_locale_buffer, locale_to_str(s_current_locales[category])); strcpy(s_locale_buffer, s_current_locales[category]->name);
break; break;
case LC_ALL: case LC_ALL:
sprintf(s_locale_buffer, "%s;%s;%s;%s;%s;%s", sprintf(s_locale_buffer, "%s;%s;%s;%s;%s;%s",
locale_to_str(s_current_locales[0]), s_current_locales[0]->name,
locale_to_str(s_current_locales[1]), s_current_locales[1]->name,
locale_to_str(s_current_locales[2]), s_current_locales[2]->name,
locale_to_str(s_current_locales[3]), s_current_locales[3]->name,
locale_to_str(s_current_locales[4]), s_current_locales[4]->name,
locale_to_str(s_current_locales[5]) s_current_locales[5]->name
); );
static_assert(LC_ALL == 6);
break; break;
default: default:
return nullptr; return nullptr;
@@ -100,7 +103,7 @@ char* setlocale(int category, const char* locale_str)
} }
locale_t locale = str_to_locale(locale_str); locale_t locale = str_to_locale(locale_str);
if (locale == LOCALE_INVALID) if (locale == nullptr)
return nullptr; return nullptr;
switch (category) switch (category)
@@ -121,7 +124,7 @@ char* setlocale(int category, const char* locale_str)
return nullptr; return nullptr;
} }
strcpy(s_locale_buffer, locale_to_str(locale)); strcpy(s_locale_buffer, locale->name);
return s_locale_buffer; return s_locale_buffer;
} }
@@ -137,6 +140,30 @@ locale_t __getlocale(int category)
case LC_TIME: case LC_TIME:
return s_current_locales[category]; return s_current_locales[category];
default: default:
return LOCALE_INVALID; return nullptr;
} }
} }
#include <BAN/Debug.h>
locale_t newlocale(int category_mask, const char* locale, locale_t base)
{
(void)category_mask;
(void)locale;
(void)base;
dwarnln("TODO: newlocale");
return nullptr;
}
void freelocale(locale_t locobj)
{
(void)locobj;
dwarnln("TODO: freelocale");
}
locale_t uselocale(locale_t newloc)
{
(void)newloc;
dwarnln("TODO: uselocale");
return nullptr;
}
+100 -41
View File
@@ -229,7 +229,11 @@ void* malloc(size_t total_size)
{ {
if (total_size >= s_mmap_threshold) if (total_size >= s_mmap_threshold)
{ {
const size_t mmap_size = sizeof(MmapAllocationHeader) + total_size; const size_t page_size = getpagesize();
size_t mmap_size = sizeof(MmapAllocationHeader) + total_size;
if (const auto rem = mmap_size % page_size)
mmap_size += page_size - rem;
void* address = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); void* address = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (address == MAP_FAILED) if (address == MAP_FAILED)
@@ -264,10 +268,12 @@ void* malloc(size_t total_size)
if (new_allocators == MAP_FAILED) if (new_allocators == MAP_FAILED)
goto malloc_return; goto malloc_return;
if (s_allocators != nullptr)
{
static_assert(BAN::is_trivially_copyable_v<BitmapAllocator>); static_assert(BAN::is_trivially_copyable_v<BitmapAllocator>);
memcpy(new_allocators, s_allocators, s_allocator_count * sizeof(BitmapAllocator)); memcpy(new_allocators, s_allocators, s_allocator_count * sizeof(BitmapAllocator));
munmap(s_allocators, s_allocator_capacity * sizeof(BitmapAllocator)); munmap(s_allocators, s_allocator_capacity * sizeof(BitmapAllocator));
}
s_allocators = static_cast<BitmapAllocator*>(new_allocators); s_allocators = static_cast<BitmapAllocator*>(new_allocators);
s_allocator_capacity = new_allocator_pages * page_size / sizeof(BitmapAllocator); s_allocator_capacity = new_allocator_pages * page_size / sizeof(BitmapAllocator);
@@ -303,51 +309,82 @@ void free(void* ptr)
const auto& header = static_cast<MmapAllocationHeader*>(ptr)[-1]; const auto& header = static_cast<MmapAllocationHeader*>(ptr)[-1];
s_mmap_count--; s_mmap_count--;
s_mmap_bytes += header.mmap_size; s_mmap_bytes -= header.mmap_size;
munmap(static_cast<uint8_t*>(ptr) - header.offset, header.mmap_size); munmap(static_cast<uint8_t*>(ptr) - header.offset, header.mmap_size);
} }
static size_t allocation_size(void* ptr)
{
pthread_mutex_lock(&s_allocator_lock);
for (size_t i = 0; i < s_allocator_count; i++)
{
if (!s_allocators[i].contains(ptr))
continue;
const size_t size = s_allocators[i].allocation_size(ptr);
pthread_mutex_unlock(&s_allocator_lock);
return size;
}
pthread_mutex_unlock(&s_allocator_lock);
const auto& header = static_cast<MmapAllocationHeader*>(ptr)[-1];
return header.mmap_size - header.offset;
}
void* realloc(void* ptr, size_t size) void* realloc(void* ptr, size_t size)
{ {
if (ptr == nullptr) if (ptr == nullptr)
return malloc(size); return malloc(size);
bool was_mmapped = true;
size_t old_alloc_size = 0;
pthread_mutex_lock(&s_allocator_lock); pthread_mutex_lock(&s_allocator_lock);
for (size_t i = 0; i < s_allocator_count; i++) for (size_t i = 0; i < s_allocator_count; i++)
{ {
if (!s_allocators[i].contains(ptr)) if (!s_allocators[i].contains(ptr))
continue; continue;
if (!s_allocators[i].resize(ptr, size)) if (s_allocators[i].resize(ptr, size))
break; {
pthread_mutex_unlock(&s_allocator_lock); pthread_mutex_unlock(&s_allocator_lock);
return ptr; return ptr;
} }
was_mmapped = false;
old_alloc_size = s_allocators[i].allocation_size(ptr);
break;
}
pthread_mutex_unlock(&s_allocator_lock); pthread_mutex_unlock(&s_allocator_lock);
// TODO: maybe an in-place realloc for mmap-backed allocations? if (was_mmapped)
{
auto& header = static_cast<MmapAllocationHeader*>(ptr)[-1];
old_alloc_size = header.mmap_size - header.offset;
if (size == old_alloc_size)
return ptr;
const size_t page_size = getpagesize();
size_t new_mmap_size = header.offset + size;
if (const auto rem = new_mmap_size % page_size)
new_mmap_size += page_size - rem;
if (size < old_alloc_size)
{
// TODO: should we drop back to bitmap based allocations if the new size is < mmap threshold?
const size_t shrink_bytes = header.mmap_size - new_mmap_size;
munmap(static_cast<uint8_t*>(ptr) - header.offset + new_mmap_size, shrink_bytes);
s_mmap_bytes -= shrink_bytes;
header.mmap_size = new_mmap_size;
return ptr;
}
const size_t extend_bytes = new_mmap_size - header.mmap_size;
void* extend_data = mmap(
static_cast<uint8_t*>(ptr) - header.offset + header.mmap_size,
extend_bytes,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE,
-1, 0
);
if (extend_data != MAP_FAILED)
{
s_mmap_bytes += extend_bytes;
header.mmap_size = new_mmap_size;
return ptr;
}
}
void* new_ptr = malloc(size); void* new_ptr = malloc(size);
if (new_ptr == nullptr) if (new_ptr == nullptr)
return nullptr; return nullptr;
memcpy(new_ptr, ptr, BAN::Math::min(allocation_size(ptr), size)); memcpy(new_ptr, ptr, BAN::Math::min(old_alloc_size, size));
free(ptr); free(ptr);
@@ -368,6 +405,7 @@ void* calloc(size_t nmemb, size_t size)
if (ptr == nullptr) if (ptr == nullptr)
return nullptr; return nullptr;
if (total < s_mmap_threshold)
memset(ptr, 0, total); memset(ptr, 0, total);
return ptr; return ptr;
} }
@@ -396,25 +434,37 @@ void* aligned_alloc(size_t alignment, size_t size)
static_assert(sizeof(MmapAllocationHeader) <= alignof(max_align_t)); static_assert(sizeof(MmapAllocationHeader) <= alignof(max_align_t));
const size_t mmap_size = alignment + size; const size_t page_size = getpagesize();
void* address = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); size_t mmap_size = alignment + size;
if (address == MAP_FAILED) if (const auto rem = mmap_size % page_size)
mmap_size += page_size - rem;
void* addr_ptr = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (addr_ptr == MAP_FAILED)
return nullptr; return nullptr;
uintptr_t addr = reinterpret_cast<uintptr_t>(addr_ptr);
uintptr_t data = addr + sizeof(MmapAllocationHeader);
if (const auto rem = data % alignment)
data += alignment - rem;
if ((data - sizeof(MmapAllocationHeader)) - addr >= page_size)
{
const size_t pages_to_free = ((data - sizeof(MmapAllocationHeader)) - addr) / page_size;
munmap(addr_ptr, pages_to_free * page_size);
mmap_size -= pages_to_free * page_size;
addr += pages_to_free * page_size;
}
s_mmap_count++; s_mmap_count++;
s_mmap_bytes += mmap_size; s_mmap_bytes += mmap_size;
uintptr_t data = reinterpret_cast<uintptr_t>(address) + sizeof(MmapAllocationHeader);
if (auto rem = data % alignment)
data += alignment - rem;
// TODO: unmap possible unused pages in alignment, they are only allocated when accessed so doesn't really matter :^)
auto& header = reinterpret_cast<MmapAllocationHeader*>(data)[-1]; auto& header = reinterpret_cast<MmapAllocationHeader*>(data)[-1];
header = { header = {
.mmap_size = mmap_size, .mmap_size = mmap_size,
.offset = data - reinterpret_cast<uintptr_t>(address), .offset = data - addr,
}; };
return &header + 1; return &header + 1;
} }
@@ -422,19 +472,28 @@ void* aligned_alloc(size_t alignment, size_t size)
int posix_memalign(void** memptr, size_t alignment, size_t size) int posix_memalign(void** memptr, size_t alignment, size_t size)
{ {
if (alignment < sizeof(void*) || !BAN::Math::is_power_of_two(alignment)) if (alignment < sizeof(void*) || !BAN::Math::is_power_of_two(alignment))
{ return EINVAL;
errno = EINVAL; return (*memptr = aligned_alloc(alignment, size)) ? 0 : errno;
return -1;
}
return (*memptr = aligned_alloc(alignment, size)) ? 0 : -1;
} }
size_t malloc_usable_size(void* ptr) size_t malloc_usable_size(void* ptr)
{ {
if (ptr == nullptr) if (ptr == nullptr)
return 0; return 0;
return allocation_size(ptr);
pthread_mutex_lock(&s_allocator_lock);
for (size_t i = 0; i < s_allocator_count; i++)
{
if (!s_allocators[i].contains(ptr))
continue;
const size_t size = s_allocators[i].allocation_size(ptr);
pthread_mutex_unlock(&s_allocator_lock);
return size;
}
pthread_mutex_unlock(&s_allocator_lock);
const auto& header = static_cast<MmapAllocationHeader*>(ptr)[-1];
return header.mmap_size - header.offset;
} }
struct mallinfo mallinfo(void) struct mallinfo mallinfo(void)
+35 -4
View File
@@ -1,5 +1,6 @@
#include <BAN/Math.h> #include <BAN/Math.h>
#include <errno.h>
#include <math.h> #include <math.h>
#include <stddef.h> #include <stddef.h>
@@ -156,6 +157,36 @@ static T1 nextafter_impl(T1 x, T2 y)
return decompose.raw; return decompose.raw;
} }
template<BAN::floating_point T>
static T ldexp_impl(T x, long e)
{
// scalb{,l}n
static_assert(FLT_RADIX == 2);
if (e == 0 || x == (T)0.0 || isnan(x) || !isfinite(x))
return x;
// TODO: handle subnormals
FloatDecompose<T> decompose(x);
if (e < 0 && decompose.bits.exponent < -e)
{
errno = ERANGE;
return BAN::Math::copysign((T)0.0, x);
}
if (e > 0 && decompose.bits.exponent > decompose.exponent_max - e)
{
errno = ERANGE;
return BAN::Math::copysign(BAN::numeric_limits<T>::infinity(), x);
}
decompose.bits.exponent += e;
return decompose.raw;
}
static long double tgamma_impl(long double x) static long double tgamma_impl(long double x)
{ {
constexpr long double pi = BAN::numbers::pi_v<long double>; constexpr long double pi = BAN::numbers::pi_v<long double>;
@@ -199,7 +230,7 @@ static long double erf_impl(long double x)
{ {
long double sum = 0.0L; long double sum = 0.0L;
for (size_t n = 0; n < 100; n++) for (size_t n = 0; n < 100; n++)
sum += x / (2.0L * n + 1.0L) * BAN::Math::ldexp(-x * x, n) / tgamma_impl(n + 1.0L); sum += x / (2.0L * n + 1.0L) * ldexp_impl(-x * x, n) / tgamma_impl(n + 1.0L);
constexpr long double sqrt_pi = 1.77245385090551602729L; constexpr long double sqrt_pi = 1.77245385090551602729L;
return 2.0L / sqrt_pi * sum; return 2.0L / sqrt_pi * sum;
@@ -237,7 +268,7 @@ BAN_FUNC2_TYPE(frexp, int*)
BAN_FUNC2(hypot) BAN_FUNC2(hypot)
FUNC_EXPR1_RET(ilogb, int, BAN::Math::logb(a)) FUNC_EXPR1_RET(ilogb, int, BAN::Math::logb(a))
// j0, j1, jn // j0, j1, jn
BAN_FUNC2_TYPE(ldexp, int) FUNC_EXPR2_TYPE(ldexp, int, ldexp_impl(a, b));
FUNC_EXPR1(lgamma, BAN::Math::log(BAN::Math::abs(tgamma_impl(a)))) FUNC_EXPR1(lgamma, BAN::Math::log(BAN::Math::abs(tgamma_impl(a))))
FUNC_EXPR1_RET(llrint, long long, BAN::Math::rint(a)) FUNC_EXPR1_RET(llrint, long long, BAN::Math::rint(a))
FUNC_EXPR1_RET(llround, long long, BAN::Math::round(a)) FUNC_EXPR1_RET(llround, long long, BAN::Math::round(a))
@@ -260,8 +291,8 @@ BAN_FUNC2(remainder)
// remquo // remquo
BAN_FUNC1(rint) BAN_FUNC1(rint)
FUNC_EXPR1(round, ({ if (!isfinite(a)) return a; BAN::Math::round(a); })) FUNC_EXPR1(round, ({ if (!isfinite(a)) return a; BAN::Math::round(a); }))
FUNC_EXPR2_TYPE(scalbln, long, BAN::Math::scalbn(a, b)) FUNC_EXPR2_TYPE(scalbln, long, ldexp_impl(a, b))
FUNC_EXPR2_TYPE(scalbn, int, BAN::Math::scalbn(a, b)) FUNC_EXPR2_TYPE(scalbn, int, ldexp_impl(a, b))
BAN_FUNC1(sin) BAN_FUNC1(sin)
BAN_FUNC1(sinh) BAN_FUNC1(sinh)
BAN_FUNC1(sqrt) BAN_FUNC1(sqrt)
+58 -48
View File
@@ -28,9 +28,11 @@ static pthread_attr_t s_default_pthread_attr {
.scope = PTHREAD_SCOPE_SYSTEM, .scope = PTHREAD_SCOPE_SYSTEM,
.stackaddr = nullptr, .stackaddr = nullptr,
.stacksize = 8 * 1024 * 1024, .stacksize = 8 * 1024 * 1024,
.guardsize = static_cast<size_t>(getpagesize()), .guardsize = 0,
}; };
static BAN::Atomic<struct uthread*> s_pending_uthread_deletion { nullptr };
static void _pthread_cancel_handler(int) static void _pthread_cancel_handler(int)
{ {
uthread* uthread = _get_uthread(); uthread* uthread = _get_uthread();
@@ -44,6 +46,8 @@ static void _pthread_cancel_handler(int)
__attribute__((constructor)) __attribute__((constructor))
static void _init_pthread() static void _init_pthread()
{ {
s_default_pthread_attr.guardsize = getpagesize();
uthread* uthread = _get_uthread(); uthread* uthread = _get_uthread();
uthread->id = syscall(SYS_THREAD_GETID); uthread->id = syscall(SYS_THREAD_GETID);
uthread->attr = s_default_pthread_attr; uthread->attr = s_default_pthread_attr;
@@ -67,9 +71,9 @@ static void _init_pthread()
const char* last_slash = strrchr(buffer, '/'); const char* last_slash = strrchr(buffer, '/');
if (last_slash == nullptr) if (last_slash == nullptr)
last_slash = buffer; last_slash = buffer - 1;
strncpy(uthread->name, last_slash, sizeof(uthread->name)); strncpy(uthread->name, last_slash + 1, sizeof(uthread->name));
uthread->name[sizeof(uthread->name) - 1] = '\0'; uthread->name[sizeof(uthread->name) - 1] = '\0';
signal(SIGCANCEL, &_pthread_cancel_handler); signal(SIGCANCEL, &_pthread_cancel_handler);
@@ -122,35 +126,18 @@ extern "C" void _pthread_trampoline_cpp(void* arg)
static void free_uthread(uthread* uthread) static void free_uthread(uthread* uthread)
{ {
const auto lock_dynamic_tls = for (size_t i = uthread->master_tls_module_count + 1; i <= uthread->dtv[0]; i++)
[uthread] {
int expected = 0;
while (BAN::atomic_compare_exchange(uthread->dynamic_tls->lock, expected, 1))
{
sched_yield();
expected = 0;
}
};
const auto unlock_dynamic_tls =
[uthread] {
BAN::atomic_store(uthread->dynamic_tls->lock, 0);
};
for (size_t i = uthread->master_tls_module_count; i < uthread->dtv[0]; i++)
{ {
if (uthread->dtv[i] == 0) if (uthread->dtv[i] == 0)
continue; continue;
munmap(
lock_dynamic_tls(); reinterpret_cast<void*>(uthread->dtv[i]),
const size_t size = uthread->dynamic_tls->entries[i].master_size; uthread->dynamic_tls->entries[i].master_size
unlock_dynamic_tls(); );
munmap(reinterpret_cast<void*>(uthread->dtv[i]), size);
} }
if (uthread->libc_owns_stack) if (uthread->libc_owns_stack)
munmap(static_cast<uint8_t*>(uthread->attr.stackaddr) - uthread->attr.guardsize, uthread->attr.guardsize + uthread->attr.stacksize); munmap(static_cast<uint8_t*>(uthread->attr.stackaddr) - uthread->attr.guardsize, uthread->attr.stacksize + uthread->attr.guardsize);
uint8_t* tls_addr = reinterpret_cast<uint8_t*>(uthread) - uthread->master_tls_size; uint8_t* tls_addr = reinterpret_cast<uint8_t*>(uthread) - uthread->master_tls_size;
const size_t tls_size = uthread->master_tls_size + sizeof(struct uthread); const size_t tls_size = uthread->master_tls_size + sizeof(struct uthread);
@@ -448,9 +435,6 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric
if (tls_addr == MAP_FAILED) if (tls_addr == MAP_FAILED)
goto pthread_create_error; goto pthread_create_error;
if (self->master_tls_addr)
memcpy(tls_addr, self->master_tls_addr, self->master_tls_size);
uthread* uthread = reinterpret_cast<struct uthread*>(tls_addr + self->master_tls_size); uthread* uthread = reinterpret_cast<struct uthread*>(tls_addr + self->master_tls_size);
*uthread = { *uthread = {
.self = uthread, .self = uthread,
@@ -473,12 +457,21 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric
}; };
strcpy(uthread->name, self->name); strcpy(uthread->name, self->name);
if (self->master_tls_addr && self->master_tls_size)
memcpy(tls_addr, self->master_tls_addr, self->master_tls_size);
const ptrdiff_t dtv_offset = reinterpret_cast<uint8_t*>(uthread) - reinterpret_cast<uint8_t*>(self);
for (size_t i = 1; i <= self->master_tls_module_count; i++)
uthread->dtv[i] = self->dtv[i] + dtv_offset;
info->uthread = uthread;
if (uthread->attr.stackaddr == nullptr) if (uthread->attr.stackaddr == nullptr)
{ {
ASSERT(uthread->attr.stacksize % getpagesize() == 0); ASSERT(uthread->attr.stacksize % getpagesize() == 0);
ASSERT(uthread->attr.guardsize % getpagesize() == 0); ASSERT(uthread->attr.guardsize % getpagesize() == 0);
void* stack_addr = mmap(nullptr, uthread->attr.guardsize + uthread->attr.stacksize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); void* stack_addr = mmap(nullptr, uthread->attr.stacksize + uthread->attr.guardsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (stack_addr == nullptr) if (stack_addr == nullptr)
goto pthread_create_error; goto pthread_create_error;
uthread->attr.stackaddr = static_cast<uint8_t*>(stack_addr) + uthread->attr.guardsize; uthread->attr.stackaddr = static_cast<uint8_t*>(stack_addr) + uthread->attr.guardsize;
@@ -488,12 +481,6 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric
goto pthread_create_error; goto pthread_create_error;
} }
const uintptr_t self_addr = reinterpret_cast<uintptr_t>(self);
const uintptr_t uthread_addr = reinterpret_cast<uintptr_t>(uthread);
for (size_t i = 1; i <= self->master_tls_module_count; i++)
uthread->dtv[i] = self->dtv[i] - self_addr + uthread_addr;
info->uthread = uthread;
result = uthread; result = uthread;
} }
@@ -558,8 +545,26 @@ void pthread_exit(void* value_ptr)
} }
if (uthread->attr.detachstate == PTHREAD_CREATE_DETACHED) if (uthread->attr.detachstate == PTHREAD_CREATE_DETACHED)
{
if (uthread->libc_owns_stack)
{
if (auto* pending = s_pending_uthread_deletion.exchange(uthread))
{
while (BAN::atomic_load(pending->id) != -1)
sched_yield();
free_uthread(pending);
}
// NOTE: after this store, our stack may get deleted but it should be *fine*
BAN::atomic_store(uthread->id, -1);
_kas_syscall(SYS_THREAD_EXIT, nullptr);
__builtin_trap();
}
free_uthread(uthread); free_uthread(uthread);
}
syscall(SYS_THREAD_EXIT, value_ptr); syscall(SYS_THREAD_EXIT, value_ptr);
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
@@ -588,10 +593,14 @@ int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
{ {
init_routine(); init_routine();
BAN::atomic_store(*once_control, 2); BAN::atomic_store(*once_control, 2);
futex(FUTEX_WAKE_PRIVATE, once_control, -1, nullptr);
}
else
{
while (BAN::atomic_load(*once_control) == 1)
futex(FUTEX_WAIT_PRIVATE, once_control, 1, nullptr);
} }
while (BAN::atomic_load(*once_control) != 2)
sched_yield();
return 0; return 0;
} }
@@ -735,11 +744,9 @@ int pthread_setcanceltype(int type, int* oldtype)
int pthread_getschedparam(pthread_t thread, int* __restrict policy, struct sched_param* __restrict param) int pthread_getschedparam(pthread_t thread, int* __restrict policy, struct sched_param* __restrict param)
{ {
(void)thread; *policy = thread->attr.schedpolicy;
(void)policy; *param = thread->attr.schedparam;
(void)param; return 0;
dwarnln("TODO: pthread_getschedparam");
return ENOTSUP;
} }
int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param) int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param)
@@ -919,11 +926,11 @@ int pthread_mutex_timedlock(pthread_mutex_t* __restrict mutex, const struct time
const int op = FUTEX_WAIT | (mutex->attr.shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME; const int op = FUTEX_WAIT | (mutex->attr.shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME;
BAN::atomic_add_fetch(mutex->waiters, 1); BAN::atomic_add_fetch(mutex->waiters, 1);
const auto ret = futex(op, &mutex->futex, expected, abstime); const auto err = futex(op, &mutex->futex, expected, abstime);
BAN::atomic_sub_fetch(mutex->waiters, 1); BAN::atomic_sub_fetch(mutex->waiters, 1);
if (ret == -1 && errno == ETIMEDOUT) if (err && err != EAGAIN)
return ETIMEDOUT; return err;
expected = 0; expected = 0;
} }
@@ -1225,8 +1232,8 @@ int pthread_cond_timedwait(pthread_cond_t* __restrict cond, pthread_mutex_t* __r
const int op = FUTEX_WAIT const int op = FUTEX_WAIT
| (cond->attr.shared ? 0 : FUTEX_PRIVATE) | (cond->attr.shared ? 0 : FUTEX_PRIVATE)
| (cond->attr.clock == CLOCK_REALTIME ? FUTEX_REALTIME : 0); | (cond->attr.clock == CLOCK_REALTIME ? FUTEX_REALTIME : 0);
if (futex(op, &block.futex, 0, abstime) == -1 && errno == ETIMEDOUT) if (const int err = futex(op, &block.futex, 0, abstime); err != EAGAIN)
ret = ETIMEDOUT; ret = err;
} }
pthread_spin_lock(&cond->lock); pthread_spin_lock(&cond->lock);
@@ -1242,6 +1249,7 @@ int pthread_cond_timedwait(pthread_cond_t* __restrict cond, pthread_mutex_t* __r
pthread_spin_unlock(&cond->lock); pthread_spin_unlock(&cond->lock);
pthread_mutex_lock(mutex); pthread_mutex_lock(mutex);
return ret; return ret;
} }
@@ -1400,6 +1408,8 @@ static void load_dynamic_tls_module(size_t module)
memcpy(dtv_data, entry.master_addr, entry.master_size); memcpy(dtv_data, entry.master_addr, entry.master_size);
if (module > uthread->dtv[0])
uthread->dtv[0]= module;
uthread->dtv[module] = reinterpret_cast<uintptr_t>(dtv_data); uthread->dtv[module] = reinterpret_cast<uintptr_t>(dtv_data);
} }
+285
View File
@@ -0,0 +1,285 @@
#include <search.h>
#include <stdlib.h>
// RB Tree implementation based on the code in wikipedia https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
struct __posix_tnode
{
const void* key;
posix_tnode* parent;
posix_tnode* children[2];
enum { RED, BLACK } color;
};
posix_tnode* tfind(const void* key, posix_tnode* const* rootp, int (*compar)(const void*, const void*))
{
if (*rootp == nullptr)
return nullptr;
posix_tnode* node = *rootp;
while (node)
{
const int result = compar(key, node->key);
if (result == 0)
return node;
node = node->children[result > 0];
}
return nullptr;
}
static posix_tnode* _trotate(posix_tnode** root, posix_tnode* node, int dir)
{
posix_tnode* old_parent = node->parent;
posix_tnode* new_root = node->children[1 - dir];
posix_tnode* new_child = new_root->children[dir];
node->children[1 - dir] = new_child;
if (new_child)
new_child->parent = node;
new_root->children[dir] = node;
new_root->parent = old_parent;
node->parent = new_root;
if (old_parent)
old_parent->children[node == old_parent->children[1]] = new_root;
else
*root = new_root;
return new_root;
}
static void _tinsert(posix_tnode** root, posix_tnode* node, posix_tnode* parent, int dir)
{
node->color = posix_tnode::RED;
node->parent = parent;
if (!parent)
{
*root = node;
return;
}
parent->children[dir] = node;
do {
if (parent->color == posix_tnode::BLACK)
return;
posix_tnode* grandparent = parent->parent;
if (!grandparent)
{
parent->color = posix_tnode::BLACK;
return;
}
dir = (parent == grandparent->children[1]);
posix_tnode* uncle = grandparent->children[1 - dir];
if (!uncle || uncle->color == posix_tnode::BLACK)
{
if (node == parent->children[1 - dir])
{
_trotate(root, parent, dir);
node = parent;
parent = grandparent->children[dir];
}
_trotate(root, grandparent, 1 - dir);
parent->color = posix_tnode::BLACK;
grandparent->color = posix_tnode::RED;
return;
}
parent->color = posix_tnode::BLACK;
uncle->color = posix_tnode::BLACK;
grandparent->color = posix_tnode::RED;
node = grandparent;
} while ((parent = node->parent));
}
posix_tnode* tsearch(const void* key, posix_tnode** root, int (*compar)(const void*, const void*))
{
posix_tnode* parent = nullptr;
posix_tnode* node = *root;
int dir = 0;
while (node)
{
const int result = compar(key, node->key);
if (result == 0)
return node;
parent = node;
dir = (result > 0);
node = node->children[dir];
}
node = static_cast<posix_tnode*>(malloc(sizeof(posix_tnode)));
if (node == nullptr)
return nullptr;
*node = {
.key = key,
.parent = nullptr,
.children = {},
.color = posix_tnode::RED,
};
_tinsert(root, node, parent, dir);
return node;
}
static void _tremove_black_leaf(posix_tnode** __restrict root, posix_tnode* node)
{
const auto case6 = [&](posix_tnode* parent, posix_tnode* sibling, posix_tnode* far_nephew, int dir) -> bool {
_trotate(root, parent, dir);
sibling->color = parent->color;
parent->color = posix_tnode::BLACK;
far_nephew->color = posix_tnode::BLACK;
return true;
};
const auto case5 = [&](posix_tnode* parent, posix_tnode* sibling, posix_tnode* near_nephew, int dir) -> bool {
_trotate(root, sibling, 1 - dir);
sibling->color = posix_tnode::RED;
near_nephew->color = posix_tnode::BLACK;
case6(parent, near_nephew, sibling, dir);
return true;
};
const auto try_case56 = [&](posix_tnode* parent, posix_tnode* sibling, int dir) -> bool {
if (posix_tnode* far_nephew = sibling->children[1 - dir]; far_nephew && far_nephew->color == posix_tnode::RED)
return case6(parent, sibling, far_nephew, dir);
if (posix_tnode* near_nephew = sibling->children[ dir]; near_nephew && near_nephew->color == posix_tnode::RED)
return case5(parent, sibling, near_nephew, dir);
return false;
};
posix_tnode* parent = node->parent;
int dir = (node == parent->children[1]);
parent->children[dir] = nullptr;
for (;;)
{
posix_tnode* sibling = parent->children[1 - dir];
if (sibling->color == posix_tnode::RED)
{
posix_tnode* near_nephew = sibling->children[dir];
_trotate(root, parent, dir);
parent->color = posix_tnode::RED;
sibling->color = posix_tnode::BLACK;
sibling = near_nephew;
if (try_case56(parent, sibling, dir))
return;
sibling->color = posix_tnode::RED;
parent->color = posix_tnode::BLACK;
return;
}
if (try_case56(parent, sibling, dir))
return;
if (parent->color == posix_tnode::RED)
{
sibling->color = posix_tnode::RED;
parent->color = posix_tnode::BLACK;
return;
}
sibling->color = posix_tnode::RED;
node = parent;
parent = node->parent;
if (parent == nullptr)
return;
dir = (node == parent->children[1]);
}
}
void* tdelete(const void* __restrict key, posix_tnode** __restrict root, int (*compar)(const void*, const void*))
{
posix_tnode* node = tfind(key, root, compar);
if (node == nullptr)
return nullptr;
// The tdelete() function shall return a pointer to the parent of the deleted node, or an unspecified non-null pointer
// if the deleted node was the root node, or a null pointer if the node is not found.
static posix_tnode dummy {};
posix_tnode* return_value = node->parent ? node->parent : &dummy;
if (node->children[0] && node->children[1])
{
posix_tnode* succ = node->children[1];
while (succ->children[0])
succ = succ->children[0];
node->key = succ->key;
node = succ;
}
posix_tnode* parent = node->parent;
posix_tnode* child = node->children[0]
? node->children[0]
: node->children[1];
if (parent == nullptr || child)
{
posix_tnode* parent = node->parent;
if (child)
{
child->parent = parent;
child->color = posix_tnode::BLACK;
}
if (parent == nullptr)
*root = child;
else
{
int dir = (node == parent->children[1]);
parent->children[dir] = child;
}
}
else if (node->color == posix_tnode::RED)
{
int dir = (node == parent->children[1]);
parent->children[dir] = nullptr;
}
else
{
_tremove_black_leaf(root, node);
}
free(node);
return return_value;
}
static void _twalk(const posix_tnode* node, void (*action)(const posix_tnode*, VISIT, int), int depth)
{
if (!node->children[0] && !node->children[1])
return action(node, leaf, depth);
action(node, preorder, depth);
if (node->children[0])
_twalk(node->children[0], action, depth + 1);
action(node, postorder, depth);
if (node->children[1])
_twalk(node->children[1], action, depth + 1);
action(node, endorder, depth);
}
void twalk(const posix_tnode* root, void (*action)(const posix_tnode*, VISIT, int))
{
if (root == nullptr)
return;
_twalk(root, action, 0);
}
+4 -1
View File
@@ -57,9 +57,12 @@ int sem_timedwait(sem_t* __restrict sem, const struct timespec* __restrict absti
} }
const int op = FUTEX_WAIT | (sem->shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME; const int op = FUTEX_WAIT | (sem->shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME;
if (futex(op, &sem->value, expected, abstime) == -1 && (errno == EINTR || errno == ETIMEDOUT)) if (const int err = futex(op, &sem->value, expected, abstime); err != EAGAIN)
{
errno = err;
return -1; return -1;
} }
}
} }
int sem_wait(sem_t* sem) int sem_wait(sem_t* sem)
+24 -26
View File
@@ -355,13 +355,12 @@ int mblen(const char* s, size_t n)
return 0; return 0;
if (n == 0) if (n == 0)
return -1; return -1;
switch (__getlocale(LC_CTYPE))
switch (__getlocale(LC_CTYPE)->encoding)
{ {
case LOCALE_INVALID: case __ENC_ASCII:
ASSERT_NOT_REACHED();
case LOCALE_POSIX:
return 1; return 1;
case LOCALE_UTF8: case __ENC_UTF8:
const auto bytes = BAN::UTF8::byte_length(*s); const auto bytes = BAN::UTF8::byte_length(*s);
if (bytes == BAN::UTF8::invalid) if (bytes == BAN::UTF8::invalid)
return -1; return -1;
@@ -369,6 +368,7 @@ int mblen(const char* s, size_t n)
return -1; return -1;
return bytes; return bytes;
} }
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
@@ -378,15 +378,13 @@ int mbtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n)
if (s == nullptr) if (s == nullptr)
return 0; return 0;
switch (__getlocale(LC_CTYPE)) switch (__getlocale(LC_CTYPE)->encoding)
{ {
case LOCALE_INVALID: case __ENC_ASCII:
ASSERT_NOT_REACHED();
case LOCALE_POSIX:
if (pwc != nullptr) if (pwc != nullptr)
*pwc = *s; *pwc = *s;
return *s ? 1 : 0; return *s ? 1 : 0;
case LOCALE_UTF8: case __ENC_UTF8:
const auto* us = reinterpret_cast<const unsigned char*>(s); const auto* us = reinterpret_cast<const unsigned char*>(s);
const uint32_t length = BAN::UTF8::byte_length(*us); const uint32_t length = BAN::UTF8::byte_length(*us);
@@ -416,17 +414,16 @@ size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n)
{ {
size_t written = 0; size_t written = 0;
switch (__getlocale(LC_CTYPE)) switch (__getlocale(LC_CTYPE)->encoding)
{ {
case LOCALE_INVALID: case __ENC_ASCII:
ASSERT_NOT_REACHED();
case LOCALE_POSIX:
if (pwcs == nullptr) if (pwcs == nullptr)
written = strlen(s); written = strlen(s);
else for (; s[written] && written < n; written++) else for (; s[written] && written < n; written++)
pwcs[written] = s[written]; pwcs[written] = s[written];
break; break;
case LOCALE_UTF8: case __ENC_UTF8:
{
const auto* us = reinterpret_cast<const unsigned char*>(s); const auto* us = reinterpret_cast<const unsigned char*>(s);
for (; *us && (pwcs == nullptr || written < n); written++) for (; *us && (pwcs == nullptr || written < n); written++)
{ {
@@ -442,6 +439,9 @@ size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n)
} }
break; break;
} }
default:
ASSERT_NOT_REACHED();
}
if (pwcs != nullptr && written < n) if (pwcs != nullptr && written < n)
pwcs[written] = L'\0'; pwcs[written] = L'\0';
@@ -454,14 +454,12 @@ int wctomb(char* s, wchar_t wchar)
if (s == nullptr) if (s == nullptr)
return 0; return 0;
switch (__getlocale(LC_CTYPE)) switch (__getlocale(LC_CTYPE)->encoding)
{ {
case locale_t::LOCALE_INVALID: case __ENC_ASCII:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
*s = wchar; *s = wchar;
return wchar ? 1 : 0; return wchar ? 1 : 0;
case locale_t::LOCALE_UTF8: case __ENC_UTF8:
char buffer[5]; char buffer[5];
if (!BAN::UTF8::from_codepoints(&wchar, 1, buffer)) if (!BAN::UTF8::from_codepoints(&wchar, 1, buffer))
return -1; return -1;
@@ -477,11 +475,9 @@ size_t wcstombs(char* __restrict s, const wchar_t* __restrict pwcs, size_t n)
{ {
size_t written = 0; size_t written = 0;
switch (__getlocale(LC_CTYPE)) switch (__getlocale(LC_CTYPE)->encoding)
{ {
case locale_t::LOCALE_INVALID: case __ENC_ASCII:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
for (size_t i = 0; pwcs[i] && (s == nullptr || written < n); i++) for (size_t i = 0; pwcs[i] && (s == nullptr || written < n); i++)
{ {
if (pwcs[i] > 0xFF) if (pwcs[i] > 0xFF)
@@ -491,7 +487,7 @@ size_t wcstombs(char* __restrict s, const wchar_t* __restrict pwcs, size_t n)
written++; written++;
} }
break; break;
case locale_t::LOCALE_UTF8: case __ENC_UTF8:
for (size_t i = 0; pwcs[i] && (s == nullptr || written < n); i++) for (size_t i = 0; pwcs[i] && (s == nullptr || written < n); i++)
{ {
char buffer[5]; char buffer[5];
@@ -507,6 +503,8 @@ size_t wcstombs(char* __restrict s, const wchar_t* __restrict pwcs, size_t n)
written += len; written += len;
} }
break; break;
default:
ASSERT_NOT_REACHED();
} }
if (s && written < n) if (s && written < n)
@@ -576,7 +574,7 @@ static void qsort_swap_generic(void* lhs, void* rhs, size_t width)
} }
} }
void qsort_swap(void* lhs, void* rhs, size_t width) static void qsort_swap(void* lhs, void* rhs, size_t width)
{ {
switch (width) switch (width)
{ {
+4 -5
View File
@@ -162,13 +162,11 @@ int strcoll(const char* s1, const char* s2)
int strcoll_l(const char *s1, const char *s2, locale_t locale) int strcoll_l(const char *s1, const char *s2, locale_t locale)
{ {
switch (locale) switch (locale->encoding)
{ {
case LOCALE_INVALID: case __ENC_ASCII:
ASSERT_NOT_REACHED();
case LOCALE_POSIX:
return strcmp(s1, s2); return strcmp(s1, s2);
case LOCALE_UTF8: case __ENC_UTF8:
{ {
const unsigned char* u1 = (unsigned char*)s1; const unsigned char* u1 = (unsigned char*)s1;
const unsigned char* u2 = (unsigned char*)s2; const unsigned char* u2 = (unsigned char*)s2;
@@ -195,6 +193,7 @@ int strcoll_l(const char *s1, const char *s2, locale_t locale)
return wc1 - wc2; return wc1 - wc2;
} }
} }
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
+20 -3
View File
@@ -1,9 +1,26 @@
#include <sys/times.h> #include <sys/times.h>
#include <time.h>
#include <unistd.h>
#include <BAN/Assert.h> static inline clock_t timespec_to_clock_t(const timespec& ts)
{
static clock_t clock_tick = -1;
if (clock_tick == -1)
clock_tick = sysconf(_SC_CLK_TCK);
return ts.tv_sec * clock_tick + ts.tv_nsec * clock_tick / 1'000'000'000;
}
clock_t times(struct tms* buffer) clock_t times(struct tms* buffer)
{ {
(void)buffer; // FIXME: system time, child times
ASSERT_NOT_REACHED(); *buffer = {};
timespec ts;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
buffer->tms_utime = timespec_to_clock_t(ts);
clock_gettime(CLOCK_MONOTONIC, &ts);
return timespec_to_clock_t(ts);
} }
+1 -1
View File
@@ -31,7 +31,7 @@ struct init_funcs_t
extern "C" char** environ; extern "C" char** environ;
#define DUMP_BACKTRACE 0 #define DUMP_BACKTRACE 1
#define DEMANGLE_BACKTRACE 0 #define DEMANGLE_BACKTRACE 0
#define BACKTRACE_SIGNALS(X) X(SIGABRT) X(SIGBUS) X(SIGFPE) X(SIGILL) X(SIGSEGV) #define BACKTRACE_SIGNALS(X) X(SIGABRT) X(SIGBUS) X(SIGFPE) X(SIGILL) X(SIGSEGV)
+15 -15
View File
@@ -45,19 +45,19 @@ size_t wcrtomb(char* __restrict s, wchar_t ws, mbstate_t* __restrict ps)
if (s == nullptr) if (s == nullptr)
return 1; return 1;
switch (__getlocale(LC_CTYPE)) switch (__getlocale(LC_CTYPE)->encoding)
{ {
case locale_t::LOCALE_INVALID: case __ENC_ASCII:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
if (ws > 0x7F) if (ws > 0x7F)
break; break;
*s = ws; *s = ws;
return 1; return 1;
case locale_t::LOCALE_UTF8: case __ENC_UTF8:
if (!BAN::UTF8::from_codepoints(&ws, 1, s)) if (!BAN::UTF8::from_codepoints(&ws, 1, s))
break; break;
return BAN::UTF8::byte_length(s[0]); return BAN::UTF8::byte_length(s[0]);
default:
ASSERT_NOT_REACHED();
} }
errno = EILSEQ; errno = EILSEQ;
@@ -74,17 +74,17 @@ size_t mbrtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n, mbst
const auto locale = __getlocale(LC_CTYPE); const auto locale = __getlocale(LC_CTYPE);
size_t bytes = -1; size_t bytes = -1;
switch (locale) switch (locale->encoding)
{ {
case locale_t::LOCALE_INVALID: case __ENC_ASCII:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
bytes = 1; bytes = 1;
break; break;
case locale_t::LOCALE_UTF8: case __ENC_UTF8:
if (auto b = BAN::UTF8::byte_length(s[0]); b != BAN::UTF8::invalid) if (auto b = BAN::UTF8::byte_length(s[0]); b != BAN::UTF8::invalid)
bytes = b; bytes = b;
break; break;
default:
ASSERT_NOT_REACHED();
} }
if (bytes == static_cast<size_t>(-1)) if (bytes == static_cast<size_t>(-1))
@@ -97,17 +97,17 @@ size_t mbrtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n, mbst
return -1; return -1;
wchar_t codepoint = WEOF; wchar_t codepoint = WEOF;
switch (locale) switch (locale->encoding)
{ {
case locale_t::LOCALE_INVALID: case __ENC_ASCII:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
codepoint = s[0]; codepoint = s[0];
break; break;
case locale_t::LOCALE_UTF8: case __ENC_UTF8:
if (auto cp = BAN::UTF8::to_codepoint(s); cp != BAN::UTF8::invalid) if (auto cp = BAN::UTF8::to_codepoint(s); cp != BAN::UTF8::invalid)
codepoint = cp; codepoint = cp;
break; break;
default:
ASSERT_NOT_REACHED();
} }
if (codepoint == WEOF) if (codepoint == WEOF)
+26 -33
View File
@@ -152,7 +152,6 @@ struct LoadedElf
ElfNativeProgramHeader tls_header; ElfNativeProgramHeader tls_header;
ElfNativeDynamic* dynamics; ElfNativeDynamic* dynamics;
uint8_t* tls_addr;
size_t tls_module; size_t tls_module;
size_t tls_offset; size_t tls_offset;
@@ -659,21 +658,21 @@ static void relocate_elf(LoadedElf& elf, bool lazy_load)
relocate_elf(*reinterpret_cast<LoadedElf*>(dynamic.d_un.d_ptr), lazy_load); relocate_elf(*reinterpret_cast<LoadedElf*>(dynamic.d_un.d_ptr), lazy_load);
} }
// do "normal" relocations // do mandatory relocations
if (elf.rel && elf.relent) if (elf.rel && elf.relent)
{
for (size_t i = 0; i < elf.relsz / elf.relent; i++) for (size_t i = 0; i < elf.relsz / elf.relent; i++)
handle_relocation(elf, *reinterpret_cast<ElfNativeRelocation*>(elf.rel + i * elf.relent), true); handle_relocation(elf, *reinterpret_cast<ElfNativeRelocation*>(elf.rel + i * elf.relent), true);
if (elf.rela && elf.relaent)
for (size_t i = 0; i < elf.relasz / elf.relaent; i++)
handle_relocation(elf, *reinterpret_cast<ElfNativeRelocationA*>(elf.rela + i * elf.relaent), true);
// do tls relocations
if (elf.rel && elf.relent)
for (size_t i = 0; i < elf.relsz / elf.relent; i++) for (size_t i = 0; i < elf.relsz / elf.relent; i++)
handle_tls_relocation(elf, *reinterpret_cast<ElfNativeRelocation*>(elf.rel + i * elf.relent)); handle_tls_relocation(elf, *reinterpret_cast<ElfNativeRelocation*>(elf.rel + i * elf.relent));
}
if (elf.rela && elf.relaent) if (elf.rela && elf.relaent)
{
for (size_t i = 0; i < elf.relasz / elf.relaent; i++)
handle_relocation(elf, *reinterpret_cast<ElfNativeRelocationA*>(elf.rela + i * elf.relaent), true);
for (size_t i = 0; i < elf.relasz / elf.relaent; i++) for (size_t i = 0; i < elf.relasz / elf.relaent; i++)
handle_tls_relocation(elf, *reinterpret_cast<ElfNativeRelocationA*>(elf.rela + i * elf.relaent)); handle_tls_relocation(elf, *reinterpret_cast<ElfNativeRelocationA*>(elf.rela + i * elf.relaent));
}
// do jumprel relocations // do jumprel relocations
if (elf.jmprel && elf.pltrelsz) if (elf.jmprel && elf.pltrelsz)
@@ -1226,7 +1225,6 @@ static MasterTLS initialize_tls_stage1()
size_t max_align = alignof(uthread); size_t max_align = alignof(uthread);
size_t tls_m_offset = 0; size_t tls_m_offset = 0;
size_t tls_m_size = 0;
size_t module_count = 0; size_t module_count = 0;
for (size_t i = 0; i < s_loaded_file_count; i++) for (size_t i = 0; i < s_loaded_file_count; i++)
{ {
@@ -1238,7 +1236,6 @@ static MasterTLS initialize_tls_stage1()
max_align = max<size_t>(max_align, tls_header.p_align); max_align = max<size_t>(max_align, tls_header.p_align);
tls_m_offset = round(tls_m_offset + tls_header.p_memsz, tls_header.p_align); tls_m_offset = round(tls_m_offset + tls_header.p_memsz, tls_header.p_align);
tls_m_size = tls_header.p_memsz;
module_count++; module_count++;
} }
@@ -1246,7 +1243,7 @@ static MasterTLS initialize_tls_stage1()
if (module_count == 0) if (module_count == 0)
return { .addr = nullptr, .size = 0, .module_count = 0 }; return { .addr = nullptr, .size = 0, .module_count = 0 };
size_t master_tls_size = tls_m_offset + tls_m_size; size_t master_tls_size = tls_m_offset;
if (auto rem = master_tls_size % max_align) if (auto rem = master_tls_size % max_align)
master_tls_size += max_align - rem; master_tls_size += max_align - rem;
@@ -1268,7 +1265,8 @@ static MasterTLS initialize_tls_stage1()
master_tls_addr = reinterpret_cast<uint8_t*>(ret); master_tls_addr = reinterpret_cast<uint8_t*>(ret);
} }
for (size_t i = 0, tls_offset = 0; i < s_loaded_file_count; i++) size_t tls_offset = 0;
for (size_t i = 0; i < s_loaded_file_count; i++)
{ {
const auto& tls_header = s_loaded_files[i].tls_header; const auto& tls_header = s_loaded_files[i].tls_header;
if (tls_header.p_type != PT_TLS) if (tls_header.p_type != PT_TLS)
@@ -1277,7 +1275,6 @@ static MasterTLS initialize_tls_stage1()
tls_offset = round(tls_offset + tls_header.p_memsz, tls_header.p_align); tls_offset = round(tls_offset + tls_header.p_memsz, tls_header.p_align);
auto& elf = s_loaded_files[i]; auto& elf = s_loaded_files[i];
elf.tls_addr = master_tls_addr + master_tls_size - tls_offset;
elf.tls_module = s_tls_module++; elf.tls_module = s_tls_module++;
elf.tls_offset = tls_offset; elf.tls_offset = tls_offset;
} }
@@ -1312,17 +1309,15 @@ static void allocate_dynamic_tls()
}; };
} }
static void initialize_tls_memory() static void initialize_master_tls_data(MasterTLS master_tls)
{ {
for (size_t i = 0; i < s_loaded_file_count; i++) for (size_t i = 0; i < s_loaded_file_count; i++)
{ {
const auto& tls_header = s_loaded_files[i].tls_header; const auto& tls_header = s_loaded_files[i].tls_header;
if (tls_header.p_type != PT_TLS) if (tls_header.p_type != PT_TLS)
continue; continue;
uint8_t* master_addr = master_tls.addr + master_tls.size - s_loaded_files[i].tls_offset;
auto& elf = s_loaded_files[i]; memcpy(master_addr, reinterpret_cast<void*>(tls_header.p_vaddr), tls_header.p_filesz);
memcpy(elf.tls_addr, reinterpret_cast<void*>(tls_header.p_vaddr), tls_header.p_filesz);
memset(elf.tls_addr + tls_header.p_filesz, 0, tls_header.p_memsz - tls_header.p_filesz);
} }
} }
@@ -1330,16 +1325,14 @@ static void initialize_tls_stage2(MasterTLS master_tls)
{ {
allocate_dynamic_tls(); allocate_dynamic_tls();
initialize_tls_memory(); initialize_master_tls_data(master_tls);
const size_t tls_size = master_tls.size + sizeof(uthread);
uint8_t* tls_addr; uint8_t* tls_addr;
{ {
const sys_mmap_t mmap_args { const sys_mmap_t mmap_args {
.addr = nullptr, .addr = nullptr,
.len = tls_size, .len = master_tls.size + sizeof(uthread),
.prot = PROT_READ | PROT_WRITE, .prot = PROT_READ | PROT_WRITE,
.flags = MAP_ANONYMOUS | MAP_PRIVATE, .flags = MAP_ANONYMOUS | MAP_PRIVATE,
.fildes = -1, .fildes = -1,
@@ -1348,14 +1341,11 @@ static void initialize_tls_stage2(MasterTLS master_tls)
const auto ret = syscall(SYS_MMAP, &mmap_args); const auto ret = syscall(SYS_MMAP, &mmap_args);
if (ret < 0) if (ret < 0)
print_error_and_exit("failed to allocate master TLS", ret); print_error_and_exit("failed to allocate TLS", ret);
tls_addr = reinterpret_cast<uint8_t*>(ret); tls_addr = reinterpret_cast<uint8_t*>(ret);
} }
memcpy(tls_addr, master_tls.addr, master_tls.size);
uthread& uthread = *reinterpret_cast<struct uthread*>(tls_addr + master_tls.size); uthread& uthread = *reinterpret_cast<struct uthread*>(tls_addr + master_tls.size);
memset(&uthread, 0, sizeof(uthread));
uthread.self = &uthread; uthread.self = &uthread;
uthread.master_tls_addr = master_tls.addr, uthread.master_tls_addr = master_tls.addr,
@@ -1375,9 +1365,11 @@ static void initialize_tls_stage2(MasterTLS master_tls)
for (size_t i = 0; i < s_loaded_file_count; i++) for (size_t i = 0; i < s_loaded_file_count; i++)
{ {
const auto& elf = s_loaded_files[i]; const auto& elf = s_loaded_files[i];
if (elf.tls_addr == nullptr) if (elf.tls_header.p_type != PT_TLS)
continue; continue;
uthread.dtv[elf.tls_module] = reinterpret_cast<uintptr_t>(tls_addr) + uthread.master_tls_size - elf.tls_offset; const ptrdiff_t offset = master_tls.size - elf.tls_offset;
memcpy(tls_addr + offset, master_tls.addr + offset, elf.tls_header.p_filesz);
uthread.dtv[elf.tls_module] = reinterpret_cast<uintptr_t>(tls_addr + offset);
} }
#if defined(__x86_64__) #if defined(__x86_64__)
@@ -1504,6 +1496,8 @@ static void register_fini_funcs(LoadedElf& elf, bool is_main_elf)
static void load_dynamic_tls(LoadedElf& elf) static void load_dynamic_tls(LoadedElf& elf)
{ {
uint8_t* tls_addr;
{ {
const sys_mmap_t mmap_args { const sys_mmap_t mmap_args {
.addr = nullptr, .addr = nullptr,
@@ -1517,12 +1511,11 @@ static void load_dynamic_tls(LoadedElf& elf)
const auto ret = syscall(SYS_MMAP, &mmap_args); const auto ret = syscall(SYS_MMAP, &mmap_args);
if (ret < 0) if (ret < 0)
print_error_and_exit("failed to allocate dynamic TLS", ret); print_error_and_exit("failed to allocate dynamic TLS", ret);
tls_addr = reinterpret_cast<uint8_t*>(ret);
elf.tls_addr = reinterpret_cast<uint8_t*>(ret);
memcpy(elf.tls_addr, reinterpret_cast<void*>(elf.tls_header.p_vaddr), elf.tls_header.p_filesz);
memset(elf.tls_addr + elf.tls_header.p_filesz, 0, elf.tls_header.p_memsz - elf.tls_header.p_filesz);
} }
memcpy(tls_addr, reinterpret_cast<void*>(elf.tls_header.p_vaddr), elf.tls_header.p_filesz);
int expected = 0; int expected = 0;
while (!BAN::atomic_compare_exchange(s_dynamic_tls->lock, expected, 1)) while (!BAN::atomic_compare_exchange(s_dynamic_tls->lock, expected, 1))
{ {
@@ -1531,7 +1524,7 @@ static void load_dynamic_tls(LoadedElf& elf)
} }
s_dynamic_tls->entries[s_dynamic_tls->entry_count++] = { s_dynamic_tls->entries[s_dynamic_tls->entry_count++] = {
.master_addr = elf.tls_addr, .master_addr = tls_addr,
.master_size = elf.tls_header.p_memsz, .master_size = elf.tls_header.p_memsz,
}; };