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/Numbers.h>
#include <BAN/Swap.h>
#include <BAN/Traits.h>
#include <float.h>
@@ -308,36 +309,6 @@ namespace BAN::Math
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>
inline constexpr T sqrt(T x)
{
@@ -470,7 +441,17 @@ namespace BAN::Math
template<floating_point T>
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
+2 -2
View File
@@ -35,13 +35,13 @@ read_user_command_line:
cmpb $'\n', %al
je .read_user_command_line_done
pushw %ax
movb %al, %bl
call isprint
testb %al, %al
jz .read_user_command_line_loop
popw %ax
movb %bl, %al
# put byte to buffer
movb %al, (%di)
+5 -3
View File
@@ -108,9 +108,11 @@ vesa_find_video_mode:
cmpb $0x4F, %al; jne .vesa_unsupported
cmpb $0x00, %ah; jne .vesa_error
# check whether in graphics mode
testb $0x10, (vesa_mode_info_buffer + 0)
jz .vesa_find_video_mode_next_mode
# check whether in graphics mode and linear framebuffer
movb (vesa_mode_info_buffer + 0), %al
andb $(0x80 | 0x10), %al
cmpb $(0x80 | 0x10), %al
jne .vesa_find_video_mode_next_mode
# compare mode's dimensions
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);
// mode
// 0: PIC
// 1: APIC
// 2: SAPIC
BAN::ErrorOr<void> enter_acpi_mode(uint8_t mode);
BAN::ErrorOr<void> enter_acpi_mode();
BAN::ErrorOr<void> initialize_acpi_devices();
+5 -4
View File
@@ -12,10 +12,10 @@ namespace Kernel
{
public:
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 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 void initialize_multiprocessor() override;
@@ -23,7 +23,7 @@ namespace Kernel
virtual void broadcast_ipi() 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 set_timer_dealine(uint64_t ns);
@@ -71,7 +71,8 @@ namespace Kernel
Kernel::vaddr_t m_local_apic_vaddr = 0;
BAN::Vector<IOAPIC> m_io_apics;
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 };
};
+5 -4
View File
@@ -28,7 +28,7 @@ namespace Kernel
BAN_NON_COPYABLE(BlockBufferWrapper);
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_callback(callback)
, m_argument(argument)
@@ -60,13 +60,13 @@ namespace Kernel
const uint8_t* data() const { return m_buffer.data(); }
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) const { return m_buffer[index]; }
private:
BAN::Span<uint8_t> m_buffer;
BAN::ByteSpan m_buffer;
void (*m_callback)(void*, const uint8_t*);
void* m_argument;
};
@@ -128,7 +128,7 @@ namespace Kernel
private:
struct BlockBuffer
{
BAN::Vector<uint8_t> buffer;
BAN::ByteSpan buffer;
bool used { false };
};
@@ -144,6 +144,7 @@ namespace Kernel
Mutex m_buffer_mutex;
ThreadBlocker m_buffer_blocker;
BAN::UniqPtr<VirtualRange> m_buffer_data;
BAN::Array<BlockBuffer, max_threads * max_buffers_per_thread> m_buffers;
BAN::Array<ThreadInfo, max_threads> m_thread_infos;
};
+2 -2
View File
@@ -14,7 +14,7 @@ namespace Kernel
virtual ~InterruptController() {}
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;
static void initialize(bool force_pic);
@@ -26,7 +26,7 @@ namespace Kernel
virtual void broadcast_ipi() = 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;
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:
virtual void lock() = 0;
virtual bool try_lock() = 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 bool is_locked_by_current_thread() const = 0;
};
class Mutex final : public BaseMutex
@@ -51,7 +49,7 @@ namespace Kernel
m_lock_depth++;
}
bool try_lock() override
bool try_lock()
{
const auto tid = Thread::current_tid();
if (tid == m_locker)
@@ -82,10 +80,10 @@ namespace Kernel
}
}
pid_t locker() const override { return m_locker; }
bool is_locked() const override { return m_locker != -1; }
pid_t locker() const { return m_locker; }
bool is_locked() const { return m_locker != -1; }
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:
BAN::Atomic<pid_t> m_locker { -1 };
@@ -126,7 +124,7 @@ namespace Kernel
m_lock_depth++;
}
bool try_lock() override
bool try_lock()
{
const auto tid = Thread::current_tid();
@@ -164,10 +162,10 @@ namespace Kernel
}
}
pid_t locker() const override { return m_locker; }
bool is_locked() const override { return m_locker != -1; }
pid_t locker() const { return m_locker; }
bool is_locked() const { return m_locker != -1; }
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:
BAN::Atomic<pid_t> m_locker { -1 };
+5 -5
View File
@@ -1,7 +1,7 @@
#pragma once
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Lock/SpinLockAsMutex.h>
namespace Kernel
{
@@ -18,8 +18,8 @@ namespace Kernel
SpinLockGuard _(m_lock);
while (m_writers_waiting > 0 || m_writer != -1)
{
SpinLockGuardAsMutex smutex(_);
m_thread_blocker.block_indefinite(&smutex);
BlockableSpinLock block(m_lock);
m_thread_blocker.block_indefinite(&block);
}
m_readers_active++;
}
@@ -44,8 +44,8 @@ namespace Kernel
m_writers_waiting++;
while (m_readers_active > 0 || m_writer != -1)
{
SpinLockGuardAsMutex smutex(_);
m_thread_blocker.block_indefinite(&smutex);
BlockableSpinLock block(m_lock);
m_thread_blocker.block_indefinite(&block);
}
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> 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> tell(int) const;
+4 -3
View File
@@ -10,10 +10,10 @@ namespace Kernel
{
public:
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 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 void initialize_multiprocessor() override;
@@ -29,7 +29,8 @@ namespace Kernel
private:
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;
};
+10 -1
View File
@@ -104,10 +104,17 @@ namespace Kernel
static void pause()
{
__builtin_ia32_pause();
if (is_smp_enabled())
if (is_smp_enabled() && !smp_messages_disabled())
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; }
paddr_t stack_top_paddr() const { return m_stack_paddr + s_stack_size; }
@@ -198,6 +205,8 @@ namespace Kernel
ProcessorID m_id { 0 };
uint8_t m_index { 0 };
bool m_smp_messages_disabled { false };
vaddr_t m_thread_syscall_stack;
Thread* m_sse_thread { nullptr };
+3 -1
View File
@@ -58,7 +58,7 @@ namespace Kernel
BAN::ErrorOr<void> initialize();
void reschedule(YieldRegisters*);
void reschedule_if_idle();
void reschedule_if_needed();
void on_timer_interrupt();
void on_yield(YieldRegisters*);
@@ -118,6 +118,8 @@ namespace Kernel
bool m_should_calculate_max_load_threads { true };
bool m_has_pending_reschedule { false };
Thread* m_idle_thread { nullptr };
friend class ThreadBlocker;
@@ -22,6 +22,7 @@ namespace Kernel
virtual void handle_irq() override;
bool supports_64bit() const { return m_supports_64bit; }
uint32_t command_slot_count() const { return m_command_slot_count; }
private:
@@ -38,9 +39,8 @@ namespace Kernel
BAN::Array<AHCIDevice*, 32> m_devices;
bool m_supports_64bit { false };
uint32_t m_command_slot_count { 0 };
friend class ATAController;
};
}
@@ -32,8 +32,6 @@
namespace Kernel
{
static constexpr uint32_t s_hba_prdt_count { 8 };
struct FISRegisterH2D
{
uint8_t fis_type; // FIS_TYPE_REGISTER_H2D
@@ -61,7 +59,8 @@ namespace Kernel
uint8_t control;
uint8_t __reserved1[4];
} __attribute__((packed));
};
static_assert(sizeof(FISRegisterH2D) == 20);
struct FISRegisterD2H
{
@@ -90,7 +89,8 @@ namespace Kernel
uint8_t __reserved3[2];
uint8_t __reserved4[4];
} __attribute__((packed));
};
static_assert(sizeof(FISRegisterD2H) == 20);
struct FISDataBI
{
@@ -102,7 +102,8 @@ namespace Kernel
uint8_t __reserved1[2];
uint32_t data[0]; // Payload (1 - 2048 dwords)
} __attribute__((packed));
};
static_assert(sizeof(FISDataBI) == 4);
struct SetDeviceBitsD2H
{
@@ -117,7 +118,8 @@ namespace Kernel
uint8_t error;
uint32_t __reserved1;
} __attribute__((packed));
};
static_assert(sizeof(SetDeviceBitsD2H) == 8);
struct PIOSetupD2H
{
@@ -149,7 +151,8 @@ namespace Kernel
uint16_t tc; // Transfer count
uint8_t __reserved4[2];
} __attribute__((packed));
};
static_assert(sizeof(PIOSetupD2H) == 20);
struct DMASetupBI
{
@@ -163,8 +166,8 @@ namespace Kernel
uint8_t __reserved1[2];
uint64_t dma_buffer_id; // 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_lo; // DMA Buffer Identifier. Used to Identify DMA buffer in host memory.
uint32_t dma_buffer_id_hi; // SATA Spec says host specific and not in Spec. Trying AHCI spec might work.
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 __reserved3;
} __attribute__((packed));
};
static_assert(sizeof(DMASetupBI) == 28);
struct HBAPortMemorySpace
{
@@ -196,7 +200,8 @@ namespace Kernel
uint32_t fbs; // FIS-based switch control
uint32_t __reserved1[11];
uint32_t vendor[4];
} __attribute__((packed));
};
static_assert(sizeof(HBAPortMemorySpace) == 128);
struct HBAGeneralMemorySpace
{
@@ -217,7 +222,8 @@ namespace Kernel
uint8_t vendor[0x100-0xA0];
HBAPortMemorySpace ports[0]; // 1 - 32 ports
} __attribute__((packed));
};
static_assert(sizeof(HBAGeneralMemorySpace) == 256);
struct ReceivedFIS
{
@@ -235,7 +241,8 @@ namespace Kernel
uint8_t ufis[64];
uint8_t __reserved[0x100-0xA0];
} __attribute__((packed));
};
static_assert(sizeof(ReceivedFIS) == 256);
struct HBACommandHeader
{
@@ -252,13 +259,14 @@ namespace Kernel
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 ctbau; // Command table descriptor base address upper 32 bits
uint32_t __reserved1[4];
} __attribute__((packed));
};
static_assert(sizeof(HBACommandHeader) == 32);
struct HBAPRDTEntry
{
@@ -269,15 +277,17 @@ namespace Kernel
uint32_t dbc : 22; // Byte count, 4M max
uint32_t __reserved1 : 9;
uint32_t i : 1; // Interrupt on completion
} __attribute__((packed));
};
static_assert(sizeof(HBAPRDTEntry) == 16);
struct HBACommandTable
{
uint8_t cfis[64];
uint8_t acmd[16];
uint8_t __reserved[48];
HBAPRDTEntry prdt_entry[s_hba_prdt_count];
} __attribute__((packed));
HBAPRDTEntry prdt_entry[0];
};
static_assert(sizeof(HBACommandTable) == 128);
enum class AHCIPortType
{
@@ -20,30 +20,39 @@ namespace Kernel
, m_port(port)
{ }
BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> allocate_buffers();
BAN::ErrorOr<void> rebase();
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> 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();
BAN::ErrorOr<void> block_until_command_completed(uint32_t command_slot);
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;
volatile HBAPortMemorySpace* const m_port;
BAN::UniqPtr<DMARegion> m_dma_region;
// Intermediate read/write buffer
// TODO: can we read straight to user buffer?
BAN::UniqPtr<DMARegion> m_data_dma_region;
Mutex m_temp_buffer_mutex;
BAN::UniqPtr<DMARegion> m_temp_buffer;
SpinLock m_command_lock;
ThreadBlocker m_command_blocker;
friend class AHCIController;
};
+13 -11
View File
@@ -6,7 +6,6 @@
#include <kernel/BootInfo.h>
#include <kernel/InterruptController.h>
#include <kernel/IO.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/Process.h>
#include <kernel/Timer/Timer.h>
@@ -935,7 +934,7 @@ acpi_release_global_lock:
return false;
}
BAN::ErrorOr<void> ACPI::enter_acpi_mode(uint8_t mode)
BAN::ErrorOr<void> ACPI::enter_acpi_mode()
{
ASSERT(!m_namespace);
@@ -1014,7 +1013,7 @@ acpi_release_global_lock:
AML::Reference arg_ref;
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;
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)));
}
dprintln("Evaluated \\_PIC({})", mode);
dprintln("Evaluated \\_PIC({})", InterruptController::get().is_using_apic() ? 1 : 0);
uint8_t irq = fadt().sci_int;
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error())
@@ -1098,14 +1097,17 @@ acpi_release_global_lock:
dprintln("Initialized ACPI interrupts");
if (auto interrupt_link_devices_or_error = m_namespace->find_device_with_eisa_id("PNP0C0F"_sv); !interrupt_link_devices_or_error.is_error())
if (InterruptController::get().is_using_apic())
{
uint64_t routed_irq_mask = 0;
auto interrupt_link_devices = interrupt_link_devices_or_error.release_value();
for (const auto& device : interrupt_link_devices)
if (auto ret = route_interrupt_link_device(device, routed_irq_mask); ret.is_error())
dwarnln("failed to route interrupt link device: {}", ret.error());
dprintln("Routed interrupt link devices");
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;
auto interrupt_link_devices = interrupt_link_devices_or_error.release_value();
for (const auto& device : interrupt_link_devices)
if (auto ret = route_interrupt_link_device(device, routed_irq_mask); ret.is_error())
dwarnln("failed to route interrupt link device: {}", ret.error());
dprintln("Routed interrupt link devices");
}
}
return {};
+32 -26
View File
@@ -487,17 +487,12 @@ namespace Kernel
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);
const uint32_t gsi = m_irq_overrides[irq];
{
int byte = gsi / 8;
int bit = gsi % 8;
ASSERT(m_reserved_gsis[byte] & (1 << bit));
}
ASSERT(m_used_gsis[gsi / 8] & (1 << (gsi % 8)));
IOAPIC* ioapic = nullptr;
for (IOAPIC& io : m_io_apics)
@@ -515,27 +510,27 @@ namespace Kernel
RedirectionEntry redir;
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2);
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.mask = 0;
// FIXME: distribute IRQs more evenly?
redir.destination = Kernel::Processor::bsp_id().as_u32();
ioapic->write(IOAPIC_REDIRS + pin * 2, redir.lo_dword);
ioapic->write(IOAPIC_REDIRS + pin * 2 + 1, redir.hi_dword);
ioapic->write(IOAPIC_REDIRS + pin * 2, redir.lo_dword);
ioapic->write(IOAPIC_REDIRS + pin * 2 + 1, redir.hi_dword);
}
bool APIC::is_in_service(uint8_t irq)
{
uint32_t dword = (irq + IRQ_VECTOR_BASE) / 32;
uint32_t bit = (irq + IRQ_VECTOR_BASE) % 32;
const uint32_t dword = (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);
}
BAN::ErrorOr<void> APIC::reserve_irq(uint8_t irq)
BAN::ErrorOr<void> APIC::reserve_irq(uint8_t irq, bool shared)
{
SpinLockGuard _(m_lock);
@@ -557,20 +552,26 @@ namespace Kernel
return BAN::Error::from_errno(EINVAL);
}
int byte = gsi / 8;
int bit = gsi % 8;
if (m_reserved_gsis[byte] & (1 << bit))
const uint8_t byte = gsi / 8;
const uint8_t mask = 1 << (gsi % 8);
if (!shared && (m_excl_gsis[byte] & mask))
{
dwarnln("GSI {} is already reserved (IRQ {})", gsi, irq);
return BAN::Error::from_errno(EFAULT);
dwarnln("GSI {} is already reserved as exclusive", gsi);
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 {};
}
// FIXME: rewrite gsi and vector reserving
// 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;
for (; irq < 0x100; irq++)
@@ -583,7 +584,7 @@ namespace Kernel
return BAN::Error::from_errno(ENOTSUP);
}
TRY(reserve_irq(irq));
TRY(reserve_irq(irq, shared));
return irq;
}
@@ -591,6 +592,7 @@ namespace Kernel
BAN::Optional<uint8_t> APIC::get_free_irq()
{
SpinLockGuard _(m_lock);
for (uint8_t irq = 0; irq < m_irq_count; irq++)
{
const uint8_t gsi = m_irq_overrides[irq];
@@ -608,13 +610,17 @@ namespace Kernel
if (!ioapic)
continue;
const uint8_t byte = gsi / 8;
const uint8_t bit = gsi % 8;
if (m_reserved_gsis[byte] & (1 << bit))
const uint8_t byte = gsi / 8;
const uint8_t mask = 1 << (gsi % 8);
if (m_used_gsis[byte] & mask)
continue;
m_reserved_gsis[byte] |= 1 << bit;
m_used_gsis[byte] |= mask;
m_excl_gsis[byte] |= mask;
return irq;
}
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));
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++)
{
auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[i];
entry.address = m_bdl_region->paddr() + bdl_size + (i % m_used_bdl_entries) * buffer_size;
entry.samples = 0;
entry.flags = 0;
bdl_entries[i] = {
.address = static_cast<uint32_t>(m_bdl_region->paddr() + bdl_size + (i % m_used_bdl_entries) * buffer_size),
.samples = 0,
.flags = 1 << 15,
};
}
bdl_entries[m_bdl_entries - 1].flags |= 1 << 14;
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];
entry.samples = sample_frames * get_channels();
entry.flags = (1 << 15);
memcpy(
reinterpret_cast<void*>(m_bdl_region->paddr_to_vaddr(entry.address)),
m_sample_data->get_data().data(),
+3 -3
View File
@@ -3,7 +3,7 @@
#include <kernel/Audio/HDAudio/Controller.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <sys/ioctl.h>
#include <sys/sysmacros.h>
@@ -65,8 +65,8 @@ namespace Kernel
while (m_sample_data->full())
{
SpinLockGuardAsMutex smutex(lock_guard);
TRY(Thread::current().block_or_eintr_indefinite(m_sample_data_blocker, &smutex));
BlockableSpinLock block(m_spinlock);
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());
+3 -3
View File
@@ -1,8 +1,8 @@
#include <kernel/Audio/HDAudio/AudioFunctionGroup.h>
#include <kernel/Audio/HDAudio/Controller.h>
#include <kernel/Audio/HDAudio/Registers.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/MMIO.h>
#include <kernel/Timer/Timer.h>
@@ -369,8 +369,8 @@ namespace Kernel
{
if (SystemTimer::get().ms_since_boot() > waketime_ms)
return BAN::Error::from_errno(ETIMEDOUT);
SpinLockGuardAsMutex smutex(sguard);
m_rb_blocker.block_with_timeout_ms(10, &smutex);
BlockableSpinLock block(m_rb_lock);
m_rb_blocker.block_with_timeout_ms(10, &block);
}
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/Lock/BlockableSpinLock.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Timer/Timer.h>
namespace Kernel
@@ -222,8 +222,8 @@ namespace Kernel
if (!m_ready_events.empty())
continue;
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_or_waketime_ns(m_thread_blocker, waketime_ns, false, &smutex));
BlockableSpinLock block(m_ready_lock);
TRY(Thread::current().block_or_eintr_or_waketime_ns(m_thread_blocker, waketime_ns, false, &block));
}
return event_count;
+3 -3
View File
@@ -7,8 +7,8 @@
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Input/InputDevice.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Process.h>
#include <kernel/Scheduler.h>
#include <kernel/Storage/StorageDevice.h>
@@ -77,8 +77,8 @@ namespace Kernel
bool expected = true;
if (!devfs->m_should_drop_disk_cache.compare_exchange(expected, false))
{
SpinLockGuardAsMutex smutex(guard);
devfs->m_disk_cache_thread_blocker.block_indefinite(&smutex);
BlockableSpinLock block(devfs->m_disk_cache_lock);
devfs->m_disk_cache_thread_blocker.block_indefinite(&block);
continue;
}
}
+16 -4
View File
@@ -624,7 +624,7 @@ namespace Kernel
continue;
buffer.used = true;
return Ext2FS::BlockBufferWrapper {
buffer.buffer.span(),
buffer.buffer,
[](void* self, const uint8_t* buffer) { static_cast<BlockBufferManager*>(self)->destroy_callback(buffer); },
this
};
@@ -635,11 +635,23 @@ namespace Kernel
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));
buffer.used = false;
m_buffers[i] = {
.buffer = buffer_data_span.slice(i * block_size, block_size),
.used = false,
};
}
return {};
}
+15 -8
View File
@@ -413,10 +413,14 @@ namespace Kernel
extern "C" void cpp_ipi_handler()
{
ASSERT(InterruptController::get().is_in_service(IRQ_IPI - IRQ_VECTOR_BASE));
InterruptController::get().eoi(IRQ_IPI - IRQ_VECTOR_BASE);
if (!InterruptController::get().is_in_service(IRQ_IPI - IRQ_VECTOR_BASE))
return;
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()
@@ -429,13 +433,17 @@ namespace Kernel
asm volatile("cli; 1: hlt; jmp 1b");
}
ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE));
InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE);
if (!InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE))
return;
if (Processor::current_is_bsp())
Process::update_alarm_queue();
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)
@@ -453,15 +461,14 @@ namespace Kernel
if (!InterruptController::get().is_in_service(irq))
return;
InterruptController::get().eoi(irq);
if (auto* handler = s_interruptables[irq])
handler->handle_irq();
else
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()
+9 -9
View File
@@ -3,7 +3,7 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/InputDevice.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Terminal/TTY.h>
#include <LibInput/Joystick.h>
@@ -245,8 +245,8 @@ namespace Kernel
while (m_event_count == 0)
{
// FIXME: should m_mutex be unlocked?
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_event_thread_blocker, &smutex));
BlockableSpinLock block(m_event_lock);
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);
@@ -289,8 +289,8 @@ namespace Kernel
if (s_tty_keyboard_events.empty())
{
SpinLockGuardAsMutex smutex(guard);
s_tty_keyboard_event_blocker.block_indefinite(&smutex);
BlockableSpinLock block(s_tty_keyboard_event_lock);
s_tty_keyboard_event_blocker.block_indefinite(&block);
continue;
}
@@ -350,8 +350,8 @@ namespace Kernel
return bytes;
}
SpinLockGuardAsMutex smutex(keyboard_guard);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex));
BlockableSpinLock block(s_keyboard_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &block));
}
}
@@ -407,8 +407,8 @@ namespace Kernel
return bytes;
}
SpinLockGuardAsMutex smutex(mouse_guard);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex));
BlockableSpinLock block(s_mouse_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &block));
}
}
+4 -4
View File
@@ -435,14 +435,14 @@ namespace Kernel::Input
devices[0] = {
.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)
{
devices[1] = {
.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] = {
.type = DeviceType::Unknown,
.interrupt = PS2::INTERRUPT_FIRST_PORT,
.interrupt = PS2::IRQ::DEVICE0,
};
devices[1] = {
.type = DeviceType::Unknown,
.interrupt = PS2::INTERRUPT_SECOND_PORT,
.interrupt = PS2::IRQ::DEVICE1,
};
}
else
-1
View File
@@ -1,4 +1,3 @@
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Networking/ARPTable.h>
#include <kernel/Scheduler.h>
#include <kernel/Timer/Timer.h>
+3 -3
View File
@@ -1,7 +1,7 @@
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
#include <kernel/IO.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/MMIO.h>
#include <kernel/Networking/E1000/E1000.h>
@@ -380,8 +380,8 @@ namespace Kernel
if (rx_current != rx_tail)
write32(REG_RDT0, rx_tail);
SpinLockGuardAsMutex smutex(guard);
m_rx_blocker.block_indefinite(&smutex);
BlockableSpinLock block(m_rx_lock);
m_rx_blocker.block_indefinite(&block);
}
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/PageTable.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Networking/ICMP.h>
#include <kernel/Networking/IPv4Layer.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/NetworkManager.h>
@@ -72,8 +72,8 @@ namespace Kernel
descriptor.state = 1;
return descriptor;
}
SpinLockGuardAsMutex smutex(guard);
m_thread_blocker.block_indefinite(&smutex);
BlockableSpinLock block(m_buffer_lock);
m_thread_blocker.block_indefinite(&block);
}
}();
@@ -118,8 +118,8 @@ namespace Kernel
m_thread_blocker.unblock();
}
SpinLockGuardAsMutex smutex(guard);
m_thread_blocker.block_indefinite(&smutex);
BlockableSpinLock block(m_buffer_lock);
m_thread_blocker.block_indefinite(&block);
}
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/RTL8169/Definitions.h>
#include <kernel/Networking/RTL8169/RTL8169.h>
@@ -218,8 +218,8 @@ namespace Kernel
SpinLockGuard guard(m_tx_lock);
while (descriptor.command & RTL8169_DESC_CMD_OWN)
{
SpinLockGuardAsMutex smutex(guard);
m_tx_blocker.block_indefinite(&smutex);
BlockableSpinLock block(m_tx_lock);
m_tx_blocker.block_indefinite(&block);
}
}
@@ -308,8 +308,8 @@ namespace Kernel
m_rx_head = (m_rx_head + 1) % m_rx_descriptor_count;
}
SpinLockGuardAsMutex smutex(rx_lock_guard);
m_rx_blocker.block_indefinite(&smutex);
BlockableSpinLock block(m_rx_lock);
m_rx_blocker.block_indefinite(&block);
}
m_rx_thread_is_dead = true;
+3 -3
View File
@@ -1,5 +1,5 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Networking/UDPSocket.h>
#include <kernel/Thread.h>
@@ -181,8 +181,8 @@ namespace Kernel
while (m_packets.empty())
{
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &smutex));
BlockableSpinLock block(m_packet_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &block));
}
auto packet_info = m_packets.front();
+32
View File
@@ -354,6 +354,35 @@ namespace Kernel
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)
{
LockGuard _(m_mutex);
@@ -376,6 +405,9 @@ namespace Kernel
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;
if (new_offset < 0)
return BAN::Error::from_errno(EINVAL);
+71 -39
View File
@@ -45,6 +45,36 @@ namespace Kernel::PCI
};
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)
{
return 0x80000000
@@ -427,9 +457,6 @@ namespace Kernel::PCI
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 =
[this]()
{
@@ -450,24 +477,33 @@ namespace Kernel::PCI
write_word(*m_offset_msi_x + 0x02, msg_ctrl);
};
const uint8_t irq = get_interrupt(index);
switch (m_interrupt_mechanism)
{
case InterruptMechanism::NONE:
ASSERT_NOT_REACHED();
case InterruptMechanism::PIN:
{
enable_pin_interrupts();
disable_msi();
disable_msi_x();
if (!InterruptController::get().is_using_apic())
write_byte(PCI_REG_IRQ_LINE, irq);
InterruptController::get().enable_irq(irq);
// TODO: allow failing
auto it = s_pci_pin_interrupts.find(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;
}
case InterruptMechanism::MSI:
{
disable_pin_interrupts();
disable_msi_x();
interruptable.set_irq(irq);
uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02);
msg_ctrl &= ~(0x07 << 4); // Only one interrupt
msg_ctrl |= 1u << 0; // Enable
@@ -495,6 +531,8 @@ namespace Kernel::PCI
disable_pin_interrupts();
disable_msi();
interruptable.set_irq(irq);
uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
msg_ctrl |= 1 << 15; // Enable
write_word(*m_offset_msi_x + 0x02, msg_ctrl);
@@ -548,7 +586,7 @@ namespace Kernel::PCI
debug_guard.disable();
auto& apic = static_cast<APIC&>(InterruptController::get());
return TRY(apic.reserve_gsi(gsi_value));
return TRY(apic.reserve_gsi(gsi_value, true));
}
else
{
@@ -587,11 +625,8 @@ namespace Kernel::PCI
if (irq_mask & (1 << irq))
break;
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error())
{
dwarnln("FIXME: irq sharing");
if (auto ret = InterruptController::get().reserve_irq(irq, true); ret.is_error())
return ret.release_error();
}
return irq;
}
@@ -621,11 +656,8 @@ namespace Kernel::PCI
debug_guard.disable();
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error())
{
dwarnln("FIXME: irq sharing");
if (auto ret = InterruptController::get().reserve_irq(irq, true); ret.is_error())
return ret.release_error();
}
return irq;
}
@@ -747,28 +779,21 @@ namespace Kernel::PCI
const auto mechanism =
[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;
if (m_offset_msi_x.has_value())
{
const uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
if (count <= (msg_ctrl & 0x7FF) + 1)
return InterruptMechanism::MSIX;
}
// MSI cannot be used without LAPIC
return InterruptMechanism::NONE;
}
if (m_offset_msi_x.has_value())
{
const uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
if (count <= (msg_ctrl & 0x7FF) + 1)
return InterruptMechanism::MSIX;
}
if (m_offset_msi.has_value())
{
if (count == 1)
return InterruptMechanism::MSI;
// FIXME: support multiple MSIs
if (m_offset_msi.has_value())
{
if (count == 1)
return InterruptMechanism::MSI;
// FIXME: support multiple MSIs
}
}
if (count == 1)
@@ -790,10 +815,17 @@ namespace Kernel::PCI
case InterruptMechanism::NONE:
ASSERT_NOT_REACHED();
case InterruptMechanism::PIN:
if (!InterruptController::get().is_using_apic())
return InterruptController::get().get_free_irq();
if (auto ret = find_intx_interrupt(); !ret.is_error())
return ret.release_value();
if (InterruptController::get().is_using_apic())
{
if (auto ret = find_intx_interrupt(); !ret.is_error())
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 {};
case InterruptMechanism::MSI:
case InterruptMechanism::MSIX:
+31 -19
View File
@@ -2,8 +2,6 @@
#include <kernel/IO.h>
#include <kernel/PIC.h>
#include <string.h>
#define PIC1_CMD 0x20
#define PIC1_DATA 0x21
#define PIC2_CMD 0xA0
@@ -76,48 +74,62 @@ namespace Kernel
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);
ASSERT(irq < 16);
ASSERT(m_reserved_irqs & (1 << irq));
if (level_triggered)
dprintln("no level triggered IRQs with PIC, using edge triggered");
uint16_t port = PIC1_DATA;
if(irq >= 8)
{
port = PIC2_DATA;
SpinLockGuard _(m_lock);
ASSERT(irq < 16);
ASSERT(m_used_irqs & (1 << irq));
const uint16_t port = [&irq]() -> uint16_t {
if (irq < 8)
return PIC1_DATA;
irq -= 8;
}
return PIC2_DATA;
}();
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)
{
dwarnln("PIC only supports 16 irqs");
return BAN::Error::from_errno(EFAULT);
}
SpinLockGuard _(m_lock);
if (m_reserved_irqs & (1 << irq))
if (!shared && (m_excl_irqs & (1 << irq)))
{
dwarnln("irq {} is already reserved", irq);
return BAN::Error::from_errno(EFAULT);
dwarnln("IRQ {} is already reserved as exclusive", irq);
return BAN::Error::from_errno(EINVAL);
}
m_reserved_irqs |= 1 << irq;
m_used_irqs |= 1 << irq;
if (!shared)
m_excl_irqs |= 1 << irq;
return {};
}
BAN::Optional<uint8_t> PIC::get_free_irq()
{
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;
m_reserved_irqs |= 1 << irq;
m_used_irqs |= 1 << irq;
m_excl_irqs |= 1 << irq;
return irq;
}
return {};
}
+6 -7
View File
@@ -10,8 +10,8 @@
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Memory/FileBackedRegion.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/MemoryBackedRegion.h>
@@ -1197,8 +1197,8 @@ namespace Kernel
if (options & WNOHANG)
return 0;
SpinLockGuardAsMutex smutex(sguard);
TRY(Thread::current().block_or_eintr_indefinite(m_child_wait_blocker, &smutex));
BlockableSpinLock block(m_child_wait_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_child_wait_blocker, &block));
}
if (user_stat_loc != nullptr)
@@ -2049,8 +2049,7 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, unsigned long request, void* arg)
{
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
return TRY(inode->ioctl(request, arg));
return m_open_file_descriptors.ioctl(fildes, request, arg);
}
BAN::ErrorOr<long> Process::sys_pselect(sys_pselect_t* user_arguments)
@@ -3172,8 +3171,8 @@ namespace Kernel
if (!m_stopped)
break;
SpinLockGuardAsMutex smutex(guard);
m_stop_blocker.block_indefinite(&smutex);
BlockableSpinLock block(m_signal_lock);
m_stop_blocker.block_indefinite(&block);
}
}
+2
View File
@@ -447,6 +447,8 @@ namespace Kernel
auto processor_id = current_id();
auto& processor = s_processors[processor_id.m_id];
ASSERT(!processor.m_smp_messages_disabled);
auto* pending = processor.m_smp_pending.exchange(nullptr);
if (pending == nullptr)
return set_interrupt_state(state);
+25 -22
View File
@@ -235,8 +235,12 @@ namespace Kernel
add_current_to_most_loaded(m_current->blocked ? &m_block_queue : &m_run_queue);
if (!m_current->blocked)
m_run_queue.add_thread_to_back(m_current);
else if (m_block_queue.add_thread_with_wake_time(m_current))
update_wake_up_deadline();
else
{
if (m_block_queue.add_thread_with_wake_time(m_current))
update_wake_up_deadline();
Processor::set_disable_smp_messages(false);
}
break;
case Thread::State::NotStarted:
ASSERT(!m_current->blocked);
@@ -306,14 +310,7 @@ namespace Kernel
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
while (!m_block_queue.empty() && current_ns >= m_block_queue.front()->wake_time_ns)
{
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);
}
unblock_thread(m_block_queue.front());
}
void Scheduler::update_wake_up_deadline()
@@ -335,12 +332,15 @@ namespace Kernel
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);
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();
}
}
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
// 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)
Processor::yield();
m_has_pending_reschedule = true;
else
update_wake_up_deadline();
}
@@ -383,14 +383,15 @@ namespace Kernel
{
if (!node->blocked)
return;
if (node != m_current)
m_block_queue.remove_node(node);
ASSERT(node != m_current);
Processor::set_disable_smp_messages(true);
m_block_queue.remove_node(node);
if (auto* blocker = node->blocker.load())
blocker->remove_thread_from_block_queue(node);
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);
Processor::set_disable_smp_messages(false);
}
else
{
@@ -602,7 +603,6 @@ namespace Kernel
}
thread_info.node->processor_id = least_loaded_id;
Processor::send_smp_message(least_loaded_id, {
.type = Processor::SMPMessage::Type::NewThread,
.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)
{
if (SystemTimer::get().ns_since_boot() >= wake_time_ns)
return;
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
ASSERT(m_current->processor_id == Processor::current_id());
ASSERT(!m_current->blocked);
Processor::set_disable_smp_messages(true);
m_current->blocked = true;
m_current->wake_time_ns = wake_time_ns;
if (blocker)
if (blocker != nullptr)
blocker->add_thread_to_block_queue(m_current);
update_most_loaded_node_queue(m_current, &m_block_queue);
uint32_t lock_depth = 0;
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();
}
+14 -12
View File
@@ -39,6 +39,7 @@ namespace Kernel
m_pci_device.enable_interrupt(0, *this);
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;
uint32_t pi = abar_mem.pi;
@@ -85,28 +86,29 @@ namespace Kernel
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;
abar_mem.is = is;
for (uint8_t i = 0; i < 32; i++)
while (uint32_t is = abar_mem.is)
{
if (is & (1 << i))
abar_mem.is = is;
while (is != 0)
{
if (m_devices[i])
m_devices[i]->handle_irq();
const size_t idx = __builtin_ctz(is);
if (auto& device = m_devices[idx])
device->handle_irq();
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)
{
uint32_t ssts = port.ssts;
uint8_t ipm = (ssts >> 8) & 0x0F;
uint8_t det = (ssts >> 0) & 0x0F;
const uint32_t ssts = port.ssts;
const uint8_t ipm = (ssts >> 8) & 0x0F;
const uint8_t det = (ssts >> 0) & 0x0F;
if (det != HBA_PORT_DET_PRESENT)
return {};
+266 -131
View File
@@ -11,6 +11,13 @@ namespace Kernel
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)
{
while (port->cmd & HBA_PxCMD_CR)
@@ -27,6 +34,27 @@ namespace Kernel
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)
{
auto* device_ptr = new AHCIDevice(controller, port);
@@ -37,57 +65,61 @@ namespace Kernel
BAN::ErrorOr<void> AHCIDevice::initialize()
{
TRY(allocate_buffers());
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
m_port->ie = 0xFFFFFFFF;
TRY(read_identify_data());
TRY(detail::ATABaseDevice::initialize({ (const uint16_t*)m_data_dma_region->vaddr(), m_data_dma_region->size() / sizeof(uint16_t) }));
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());
TRY(detail::ATABaseDevice::initialize({ reinterpret_cast<const uint16_t*>(m_temp_buffer->vaddr()), 256 }));
return {};
}
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);
uint64_t fis_paddr = m_dma_region->paddr();
m_port->fb = fis_paddr & 0xFFFFFFFF;
m_port->fbu = fis_paddr >> 32;
const paddr_t command_list_paddr = m_dma_region->paddr();
write_paddr(m_port->clb, m_port->clbu, command_list_paddr);
uint64_t command_list_paddr = fis_paddr + sizeof(ReceivedFIS);
m_port->clb = command_list_paddr & 0xFFFFFFFF;
m_port->clbu = command_list_paddr >> 32;
volatile auto* command_list = reinterpret_cast<volatile HBACommandHeader*>(m_dma_region->paddr_to_vaddr(command_list_paddr));
const paddr_t command_table_base = command_list_paddr + command_slot_count * sizeof(HBACommandHeader);
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);
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;
}
write_paddr(m_port->fb, m_port->fbu, m_dma_region->paddr() + fis_offset);
start_cmd(m_port);
@@ -96,37 +128,26 @@ namespace Kernel
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;
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.w = 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];
command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t);
command_header.w = 0;
command_header.prdtl = 1;
volatile auto& command_table = *reinterpret_cast<volatile HBACommandTable*>(m_dma_region->paddr_to_vaddr(command_header.ctba));
memset(const_cast<HBACommandTable*>(&command_table), 0x00, sizeof(HBACommandTable));
command_table.prdt_entry[0].dba = m_data_dma_region->paddr();
const vaddr_t command_table_vaddr = m_dma_region->paddr_to_vaddr(read_paddr(command_header.ctba, command_header.ctbau));
volatile auto& command_table = *reinterpret_cast<volatile HBACommandTable*>(command_table_vaddr);
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].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.c = 1;
command.command = ATA_COMMAND_IDENTIFY;
command.c = 1;
command.command = ATA_COMMAND_IDENTIFY;
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + s_ata_timeout_ms;
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()));
TRY(send_command_and_wait(slot));
return {};
}
@@ -150,49 +171,64 @@ namespace Kernel
void AHCIDevice::handle_irq()
{
const uint32_t is = m_port->is;
m_port->is = is;
const uint32_t serr = m_port->serr;
m_port->serr = serr;
if (auto err = serr & 0xFFFF)
print_error(err);
}
BAN::ErrorOr<void> AHCIDevice::block_until_command_completed(uint32_t command_slot)
{
static constexpr uint64_t poll_timeout_ms = 10;
const auto start_time_ms = SystemTimer::get().ms_since_boot();
while (SystemTimer::get().ms_since_boot() < start_time_ms + poll_timeout_ms)
if (!(m_port->ci & (1 << command_slot)))
return {};
// FIXME: This should actually block once ThreadBlocker support blocking with timeout.
// This doesn't allow scheduler to go properly idle.
while (SystemTimer::get().ms_since_boot() < start_time_ms + s_ata_timeout_ms)
while (const uint32_t is = m_port->is)
{
Processor::yield();
if (!(m_port->ci & (1 << command_slot)))
return {};
m_prev_is |= is;
m_port->is = is;
SpinLockGuard _(m_command_lock);
m_command_blocker.unblock();
}
return BAN::Error::from_errno(ETIMEDOUT);
if (const uint32_t serr = m_port->serr & 0xFFFF)
{
m_port->serr = serr;
print_error(serr);
}
}
bool AHCIDevice::can_use_buffer_directly(BAN::ConstByteSpan buffer) const
{
const vaddr_t buffer_vaddr = reinterpret_cast<vaddr_t>(buffer.data());
if (buffer_vaddr % 2)
return false;
if (m_controller->supports_64bit())
return true;
const vaddr_t buffer_base = buffer_vaddr & PAGE_ADDR_MASK;
for (size_t off = 0; off < buffer.size(); off++)
if (PageTable::kernel().physical_address_of(buffer_base + off) >= 0x100000000)
return false;
return true;
}
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());
const size_t sectors_per_page = PAGE_SIZE / sector_size();
for (uint64_t sector_off = 0; sector_off < sector_count; sector_off += sectors_per_page)
{
uint64_t to_read = BAN::Math::min<uint64_t>(sector_count - sector_off, sectors_per_page);
if (buffer.size() > sector_count * sector_size())
buffer = buffer.slice(0, sector_count * sector_size());
TRY(send_command_and_block(lba + sector_off, to_read, Command::Read));
memcpy(buffer.data() + sector_off * sector_size(), (void*)m_data_dma_region->vaddr(), to_read * sector_size());
if (can_use_buffer_directly(buffer))
{
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 {};
@@ -200,37 +236,43 @@ namespace Kernel
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());
const size_t sectors_per_page = PAGE_SIZE / sector_size();
for (uint64_t sector_off = 0; sector_off < sector_count; sector_off += sectors_per_page)
{
uint64_t to_read = BAN::Math::min<uint64_t>(sector_count - sector_off, sectors_per_page);
if (buffer.size() > sector_count * sector_size())
buffer = buffer.slice(0, sector_count * sector_size());
memcpy((void*)m_data_dma_region->vaddr(), buffer.data() + sector_off * sector_size(), to_read * sector_size());
TRY(send_command_and_block(lba + sector_off, to_read, Command::Write));
if (can_use_buffer_directly(buffer))
{
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 {};
}
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_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;
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()];
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];
command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t);
command_header.prdtl = 1;
switch (command)
{
case Command::Read:
@@ -243,20 +285,66 @@ namespace Kernel
ASSERT_NOT_REACHED();
}
volatile auto& command_table = *reinterpret_cast<HBACommandTable*>(m_dma_region->paddr_to_vaddr(command_header.ctba));
memset(const_cast<HBACommandTable*>(&command_table), 0x00, sizeof(HBACommandTable));
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;
const vaddr_t command_table_vaddr = m_dma_region->paddr_to_vaddr(read_paddr(command_header.ctba, command_header.ctbau));
volatile auto& command_table = *reinterpret_cast<volatile HBACommandTable*>(command_table_vaddr);
volatile auto& fis_command = *reinterpret_cast<volatile FISRegisterH2D*>(command_table.cfis);
memset(const_cast<FISRegisterH2D*>(&fis_command), 0x00, sizeof(FISRegisterH2D));
size_t prdt_count = 0;
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.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));
switch (command)
@@ -283,23 +371,70 @@ namespace Kernel
fis_command.count_lo = (sector_count >> 0) & 0xFF;
fis_command.count_hi = (sector_count >> 8) & 0xFF;
while (m_port->tfd & (ATA_STATUS_BSY | ATA_STATUS_DRQ))
continue;
TRY(send_command_and_wait(slot));
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 {};
}
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;
for (uint32_t i = 0; i < m_controller->command_slot_count(); i++)
if (!(slots & (1 << i)))
return i;
return {};
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + s_ata_timeout_ms;
SpinLockGuard _(m_command_lock);
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/Thread.h>
#include <kernel/Timer/Timer.h>
@@ -91,8 +91,8 @@ namespace Kernel
while (~m_used_mask == 0)
{
SpinLockGuardAsMutex smutex(guard);
m_thread_blocker.block_with_timeout_ms(s_nvme_command_timeout_ms, &smutex);
BlockableSpinLock block(m_lock);
m_thread_blocker.block_with_timeout_ms(s_nvme_command_timeout_ms, &block);
}
uint16_t cid = 0;
+7 -5
View File
@@ -79,17 +79,19 @@ namespace Kernel
if (!device)
return BAN::Error::from_errno(ENODEV);
if (offset % device->blksize() || buffer.size() % device->blksize())
return BAN::Error::from_errno(ENOTSUP);
if (offset < 0 || offset % device->blksize())
return BAN::Error::from_errno(EINVAL);
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1;
uint32_t first_block = offset / device->blksize();
uint32_t block_count = buffer.size() / device->blksize();
const uint64_t blocks_in_partition = m_last_block - m_first_block + 1;
const uint64_t first_block = offset / device->blksize();
uint64_t block_count = buffer.size() / device->blksize();
if (first_block >= blocks_in_partition)
return 0;
if (first_block + block_count > blocks_in_partition)
block_count = blocks_in_partition - first_block;
if (block_count == 0)
return 0;
TRY(read_blocks(first_block, block_count, buffer));
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)
{
if (offset % sector_size())
if (offset < 0 || offset % sector_size())
return BAN::Error::from_errno(EINVAL);
if (buffer.size() % sector_size())
return BAN::Error::from_errno(EINVAL);
TRY(read_sectors(offset / sector_size(), buffer.size() / sector_size(), buffer));
return buffer.size();
const uint64_t total_blocks = total_size() / sector_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)
{
if (offset % sector_size())
if (offset < 0 || offset % sector_size())
return BAN::Error::from_errno(EINVAL);
if (buffer.size() % sector_size())
return BAN::Error::from_errno(EINVAL);
TRY(write_sectors(offset / sector_size(), buffer.size() / sector_size(), buffer));
return buffer.size();
const uint64_t total_blocks = total_size() / sector_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/FS/DevFS/FileSystem.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Lock/BlockableSpinLock.h>
#include <kernel/Terminal/PseudoTerminal.h>
#include <BAN/ScopeGuard.h>
@@ -112,8 +112,8 @@ namespace Kernel
while (m_buffer_size == 0)
{
SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &smutex));
BlockableSpinLock block(m_buffer_lock);
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &block));
}
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/Input/InputDevice.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Process.h>
#include <kernel/Terminal/TTY.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);
if (is_interrupted_by_signal(true))
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 {};
}
+1 -1
View File
@@ -230,7 +230,7 @@ static void init2(void*)
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());
if (auto ret = ACPI::ACPI::get().initialize_acpi_devices(); ret.is_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'
VERSION='2.17.1'
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=(
'-Dprefix=/usr'
'-Dbuildtype=release'
@@ -26,23 +26,3 @@ build() {
install() {
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
NAME='gcc'
VERSION='15.2.0'
DOWNLOAD_URL="https://ftpmirror.gnu.org/gnu/gcc/gcc-$VERSION/gcc-$VERSION.tar.xz#438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e"
VERSION='15.3.0'
DOWNLOAD_URL="https://ftpmirror.gnu.org/gnu/gcc/gcc-$VERSION/gcc-$VERSION.tar.xz#fa59c1beef8995f27c4d71c1df227587189315d3e6faff1bb4306e61b0c530eb"
DEPENDENCIES=('binutils' 'gmp' 'mpfr' 'mpc')
MAKE_INSTALL_TARGETS=('install-strip-gcc' 'install-strip-target-libgcc' 'install-strip-target-libstdc++-v3')
CONFIGURE_OPTIONS=(
@@ -1,7 +1,7 @@
diff -ruN gcc-12.2.0/gcc/configure gcc-12.2.0-banan_os/gcc/configure
--- gcc-12.2.0/gcc/configure 2022-08-19 11:09:52.736664469 +0300
+++ gcc-12.2.0-banan_os/gcc/configure 2024-08-08 09:30:58.730876253 +0300
@@ -9426,6 +9426,7 @@
diff -ruN gcc-15.3.0/gcc/configure gcc-15.3.0-banan_os/gcc/configure
--- gcc-15.3.0/gcc/configure 2026-06-12 09:09:06.318521299 +0300
+++ gcc-15.3.0-banan_os/gcc/configure 2026-07-09 22:14:04.081210055 +0300
@@ -9610,6 +9610,7 @@
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
$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
NAME='lynx'
VERSION='2.9.2'
DOWNLOAD_URL="https://invisible-island.net/archives/lynx/tarballs/lynx$VERSION.tar.gz#99f8f28f860094c533100d1cedf058c27fb242ce25e991e2d5f30ece4457a3bf"
VERSION='2.9.3'
DOWNLOAD_URL="https://invisible-island.net/archives/lynx/tarballs/lynx$VERSION.tar.gz#6e99e46980974a6d89eceefbb26ca8c7aa7702b78ecb5bad383b859af225d052"
TAR_CONTENT="lynx$VERSION"
DEPENDENCIES=('ncurses' 'openssl' 'zlib')
CONFIG_SUB=('config.sub')
DEPENDENCIES=('ncurses' 'openssl' 'libiconv' 'bzip2' 'zlib' 'zstd')
CONFIGURE_OPTIONS=(
'--without-system-type'
'--with-sceen=ncurses'
'--with-screen=ncurses'
'--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"
'--enable-pc-files'
'--enable-sigwinch'
'--disable-widec'
'--with-shared'
'--with-trace'
'--without-tests'
'--without-ada'
'--without-manpages'
CFLAGS='-std=c17'
)
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"
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() {
baseq2_tar=../baseq2.tar.gz
baseq2_hash=9660c306d9440ff7d534f165ae4a7f550b9e879d5190830953034ebda10e873a
local cflags='-Dstricmp=strcasecmp -O2 -ffast-math -Wno-incompatible-pointer-types -Wno-pointer-to-int-cast'
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 ! echo "$baseq2_hash $baseq2_tar" | sha256sum --check >/dev/null; then
@@ -25,9 +30,6 @@ build() {
echo "File hash does not match" >&2
exit 1
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() {
@@ -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_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_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
--- gcc-15.2.0/config.sub 2025-08-25 18:08:25.524209333 +0300
+++ gcc-15.2.0-banan_os/config.sub 2025-08-25 18:09:09.160072736 +0300
diff -ruN gcc-15.3.0/config.sub gcc-15.3.0-banan_os/config.sub
--- gcc-15.3.0/config.sub 2026-06-12 09:09:05.607510293 +0300
+++ gcc-15.3.0-banan_os/config.sub 2026-07-09 21:47:07.527710452 +0300
@@ -1749,7 +1749,7 @@
| onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
| 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
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
--- gcc-15.2.0/fixincludes/mkfixinc.sh 2025-08-25 18:08:42.043663414 +0300
+++ gcc-15.2.0-banan_os/fixincludes/mkfixinc.sh 2025-08-25 18:09:09.191771254 +0300
diff -ruN gcc-15.3.0/fixincludes/mkfixinc.sh gcc-15.3.0-banan_os/fixincludes/mkfixinc.sh
--- gcc-15.3.0/fixincludes/mkfixinc.sh 2026-06-12 09:09:05.644510866 +0300
+++ gcc-15.3.0-banan_os/fixincludes/mkfixinc.sh 2026-07-09 21:47:07.527995337 +0300
@@ -11,6 +11,7 @@
# 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* | \
*-mingw32* | \
powerpc-*-eabisim* | \
diff -ruN gcc-15.2.0/gcc/config/banan_os.h gcc-15.2.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.2.0-banan_os/gcc/config/banan_os.h 2025-08-25 18:09:09.192159227 +0300
diff -ruN gcc-15.3.0/gcc/config/banan_os.h gcc-15.3.0-banan_os/gcc/config/banan_os.h
--- gcc-15.3.0/gcc/config/banan_os.h 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.3.0-banan_os/gcc/config/banan_os.h 2026-07-09 21:47:07.528236221 +0300
@@ -0,0 +1,35 @@
+/* Useful if you wish to make target-specific GCC changes. */
+#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=posix"); \
+ } while(0);
diff -ruN gcc-15.2.0/gcc/config/banan_os.opt gcc-15.2.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.2.0-banan_os/gcc/config/banan_os.opt 2025-08-25 18:09:09.192299819 +0300
diff -ruN gcc-15.3.0/gcc/config/banan_os.opt gcc-15.3.0-banan_os/gcc/config/banan_os.opt
--- gcc-15.3.0/gcc/config/banan_os.opt 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.3.0-banan_os/gcc/config/banan_os.opt 2026-07-09 21:47:07.528330648 +0300
@@ -0,0 +1,32 @@
+; 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
+
+; 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
--- gcc-15.2.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
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.3.0/gcc/config/banan_os.opt.urls 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.3.0-banan_os/gcc/config/banan_os.opt.urls 2026-07-09 21:47:07.528429404 +0300
@@ -0,0 +1 @@
+; 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
--- gcc-15.2.0/gcc/config.gcc 2025-08-25 18:08:36.953184232 +0300
+++ gcc-15.2.0-banan_os/gcc/config.gcc 2025-08-25 18:09:09.193116622 +0300
diff -ruN gcc-15.3.0/gcc/config.gcc gcc-15.3.0-banan_os/gcc/config.gcc
--- gcc-15.3.0/gcc/config.gcc 2026-06-12 09:09:06.107518032 +0300
+++ gcc-15.3.0-banan_os/gcc/config.gcc 2026-07-09 21:47:07.528829877 +0300
@@ -723,6 +723,14 @@
# 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*)
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"
diff -ruN gcc-15.2.0/libgcc/config/t-slibgcc gcc-15.2.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.2.0-banan_os/libgcc/config/t-slibgcc 2025-08-25 18:09:09.206796796 +0300
diff -ruN gcc-15.3.0/libgcc/config/t-slibgcc gcc-15.3.0-banan_os/libgcc/config/t-slibgcc
--- gcc-15.3.0/libgcc/config/t-slibgcc 2026-06-12 09:09:10.055579142 +0300
+++ gcc-15.3.0-banan_os/libgcc/config/t-slibgcc 2026-07-09 21:47:07.529617134 +0300
@@ -26,7 +26,6 @@
SHLIB_OBJS = @shlib_objs@
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_INSTALL_SOLINK = $(LN_S) $(SHLIB_SONAME) \
$(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
--- gcc-15.2.0/libgcc/config.host 2025-08-25 18:08:42.103193239 +0300
+++ gcc-15.2.0-banan_os/libgcc/config.host 2025-08-25 18:09:09.221444143 +0300
diff -ruN gcc-15.3.0/libgcc/config.host gcc-15.3.0-banan_os/libgcc/config.host
--- gcc-15.3.0/libgcc/config.host 2026-06-12 09:09:09.987578090 +0300
+++ gcc-15.3.0-banan_os/libgcc/config.host 2026-07-09 21:47:07.529840209 +0300
@@ -627,6 +627,14 @@
fixed_point=no
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*)
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"
diff -ruN gcc-15.2.0/libstdc++-v3/acinclude.m4 gcc-15.2.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.2.0-banan_os/libstdc++-v3/acinclude.m4 2025-08-25 18:09:09.241116556 +0300
diff -ruN gcc-15.3.0/libstdc++-v3/acinclude.m4 gcc-15.3.0-banan_os/libstdc++-v3/acinclude.m4
--- gcc-15.3.0/libstdc++-v3/acinclude.m4 2026-06-12 09:09:10.698589095 +0300
+++ gcc-15.3.0-banan_os/libstdc++-v3/acinclude.m4 2026-07-09 21:47:07.530425483 +0300
@@ -1792,7 +1792,7 @@
ac_has_nanosleep=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_realtime=yes
ac_has_nanosleep=yes
diff -ruN gcc-15.2.0/libstdc++-v3/configure gcc-15.2.0-banan_os/libstdc++-v3/configure
--- gcc-15.2.0/libstdc++-v3/configure 2025-08-25 18:08:47.550144038 +0300
+++ gcc-15.2.0-banan_os/libstdc++-v3/configure 2025-08-25 18:09:09.262116528 +0300
diff -ruN gcc-15.3.0/libstdc++-v3/configure gcc-15.3.0-banan_os/libstdc++-v3/configure
--- gcc-15.3.0/libstdc++-v3/configure 2026-06-12 09:09:10.726589529 +0300
+++ gcc-15.3.0-banan_os/libstdc++-v3/configure 2026-07-09 21:47:07.538829690 +0300
@@ -15784,8 +15784,8 @@
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_realtime=yes
ac_has_nanosleep=yes
@@ -28654,7 +28654,7 @@
@@ -28676,7 +28676,7 @@
# 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_ASINF 1" >>confdefs.h
diff -ruN gcc-15.2.0/libstdc++-v3/crossconfig.m4 gcc-15.2.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.2.0-banan_os/libstdc++-v3/crossconfig.m4 2025-08-25 18:09:09.263116526 +0300
diff -ruN gcc-15.3.0/libstdc++-v3/crossconfig.m4 gcc-15.3.0-banan_os/libstdc++-v3/crossconfig.m4
--- gcc-15.3.0/libstdc++-v3/crossconfig.m4 2026-06-12 09:09:10.727589544 +0300
+++ gcc-15.3.0-banan_os/libstdc++-v3/crossconfig.m4 2026-07-09 21:47:07.540758931 +0300
@@ -9,7 +9,7 @@
# This is a freestanding configuration; there is nothing to do here.
;;
+1
View File
@@ -32,6 +32,7 @@ set(LIBC_SOURCES
regex.cpp
scanf_impl.cpp
sched.cpp
search.cpp
semaphore.cpp
setjmp.cpp
signal.cpp
@@ -7,10 +7,13 @@
__BEGIN_DECLS
#ifndef __locale_t_defined
#define __locale_t_defined 1
typedef enum { LOCALE_INVALID, LOCALE_POSIX, LOCALE_UTF8 } locale_t;
#endif
typedef enum { __ENC_ASCII, __ENC_UTF8 } __encoding_e;
struct __locale_t
{
const char* name;
__encoding_e encoding;
};
typedef struct __locale_t* locale_t;
__END_DECLS
@@ -13,7 +13,7 @@ __BEGIN_DECLS
#include <stdint.h>
typedef int pthread_once_t;
typedef uint32_t pthread_once_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
+20 -12
View File
@@ -1,7 +1,7 @@
#ifndef _SEARCH_H
#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>
@@ -19,17 +19,25 @@ typedef struct
typedef enum { FIND, ENTER } ACTION;
typedef enum { preorder, postorder, endorder, leaf } VISIT;
int hcreate(size_t nel);
void hdestroy(void);
ENTRY* hsearch(ENTRY item, ACTION action);
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* lsearch(const void* key, void* base, size_t* nelp, size_t width, int (*compar)(const void*, const void*));
void remque(void* element);
void* tdelete(const void* __restrict key, void** __restrict rootp, int(*compar)(const void*, const void*));
void* tfind(const void* key, void* const* rootp, int(*compar)(const void*, const void*));
void* tsearch(const void* key, void** rootp, int(*compar)(const void*, const void*));
void twalk(const void* root, void (*action)(const void*, VISIT, int));
// 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);
void hdestroy(void);
ENTRY* hsearch(ENTRY item, ACTION action);
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* lsearch(const void* key, void* base, size_t* nelp, size_t width, int (*compar)(const void*, const void*));
void remque(void* element);
void* tdelete(const void* __restrict key, posix_tnode** __restrict rootp, int (*compar)(const void*, const void*));
posix_tnode* tfind(const void* key, posix_tnode* const* 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 posix_tnode* root, void (*action)(const posix_tnode*, VISIT, int));
__END_DECLS
@@ -7,6 +7,8 @@ __BEGIN_DECLS
#include <stdint.h>
#include <bits/types/winsize.h>
#define I_ATMARK 1
#define I_CANPUT 2
#define I_CKBAND 3
+2 -8
View File
@@ -10,6 +10,8 @@ __BEGIN_DECLS
#define __need_pid_t
#include <sys/types.h>
#include <bits/types/winsize.h>
typedef unsigned int cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
@@ -39,14 +41,6 @@ struct termios
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 ICRNL 0x002
#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
if (item == CODESET)
{
switch (__getlocale(LC_CTYPE))
switch (__getlocale(LC_CTYPE)->encoding)
{
case LOCALE_INVALID: ASSERT_NOT_REACHED();
case LOCALE_UTF8: return "UTF-8";
case LOCALE_POSIX: return "ANSI_X3.4-1968";
case __ENC_ASCII: return "ANSI_X3.4-1968";
case __ENC_UTF8: return "UTF-8";
}
ASSERT_NOT_REACHED();
}
+56 -29
View File
@@ -5,35 +5,37 @@
#include <stdio.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] {
LOCALE_POSIX,
LOCALE_POSIX,
LOCALE_POSIX,
LOCALE_POSIX,
LOCALE_POSIX,
LOCALE_POSIX,
&s_locale_posix,
&s_locale_posix,
&s_locale_posix,
&s_locale_posix,
&s_locale_posix,
&s_locale_posix,
};
static_assert(LC_ALL == 6);
static locale_t str_to_locale(const char* locale)
{
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)
return LOCALE_UTF8;
return LOCALE_INVALID;
}
return &s_locale_utf8;
static const char* locale_to_str(locale_t locale)
{
if (locale == LOCALE_POSIX)
return "C";
if (locale == LOCALE_UTF8)
return "C.UTF-8";
ASSERT_NOT_REACHED();
return nullptr;
}
struct lconv* localeconv(void)
@@ -80,17 +82,18 @@ char* setlocale(int category, const char* locale_str)
case LC_MONETARY:
case LC_NUMERIC:
case LC_TIME:
strcpy(s_locale_buffer, locale_to_str(s_current_locales[category]));
strcpy(s_locale_buffer, s_current_locales[category]->name);
break;
case LC_ALL:
sprintf(s_locale_buffer, "%s;%s;%s;%s;%s;%s",
locale_to_str(s_current_locales[0]),
locale_to_str(s_current_locales[1]),
locale_to_str(s_current_locales[2]),
locale_to_str(s_current_locales[3]),
locale_to_str(s_current_locales[4]),
locale_to_str(s_current_locales[5])
s_current_locales[0]->name,
s_current_locales[1]->name,
s_current_locales[2]->name,
s_current_locales[3]->name,
s_current_locales[4]->name,
s_current_locales[5]->name
);
static_assert(LC_ALL == 6);
break;
default:
return nullptr;
@@ -100,7 +103,7 @@ char* setlocale(int category, const char* locale_str)
}
locale_t locale = str_to_locale(locale_str);
if (locale == LOCALE_INVALID)
if (locale == nullptr)
return nullptr;
switch (category)
@@ -121,7 +124,7 @@ char* setlocale(int category, const char* locale_str)
return nullptr;
}
strcpy(s_locale_buffer, locale_to_str(locale));
strcpy(s_locale_buffer, locale->name);
return s_locale_buffer;
}
@@ -137,6 +140,30 @@ locale_t __getlocale(int category)
case LC_TIME:
return s_current_locales[category];
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;
}
+106 -47
View File
@@ -229,7 +229,11 @@ void* malloc(size_t total_size)
{
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);
if (address == MAP_FAILED)
@@ -264,10 +268,12 @@ void* malloc(size_t total_size)
if (new_allocators == MAP_FAILED)
goto malloc_return;
static_assert(BAN::is_trivially_copyable_v<BitmapAllocator>);
memcpy(new_allocators, s_allocators, s_allocator_count * sizeof(BitmapAllocator));
munmap(s_allocators, s_allocator_capacity * sizeof(BitmapAllocator));
if (s_allocators != nullptr)
{
static_assert(BAN::is_trivially_copyable_v<BitmapAllocator>);
memcpy(new_allocators, s_allocators, s_allocator_count * sizeof(BitmapAllocator));
munmap(s_allocators, s_allocator_capacity * sizeof(BitmapAllocator));
}
s_allocators = static_cast<BitmapAllocator*>(new_allocators);
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];
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);
}
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)
{
if (ptr == nullptr)
return malloc(size);
bool was_mmapped = true;
size_t old_alloc_size = 0;
pthread_mutex_lock(&s_allocator_lock);
for (size_t i = 0; i < s_allocator_count; i++)
{
if (!s_allocators[i].contains(ptr))
continue;
if (!s_allocators[i].resize(ptr, size))
break;
pthread_mutex_unlock(&s_allocator_lock);
return ptr;
if (s_allocators[i].resize(ptr, size))
{
pthread_mutex_unlock(&s_allocator_lock);
return ptr;
}
was_mmapped = false;
old_alloc_size = s_allocators[i].allocation_size(ptr);
break;
}
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);
if (new_ptr == 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);
@@ -368,7 +405,8 @@ void* calloc(size_t nmemb, size_t size)
if (ptr == nullptr)
return nullptr;
memset(ptr, 0, total);
if (total < s_mmap_threshold)
memset(ptr, 0, total);
return ptr;
}
@@ -396,25 +434,37 @@ void* aligned_alloc(size_t alignment, size_t size)
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);
if (address == MAP_FAILED)
size_t mmap_size = alignment + size;
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;
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_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];
header = {
.mmap_size = mmap_size,
.offset = data - reinterpret_cast<uintptr_t>(address),
.offset = data - addr,
};
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)
{
if (alignment < sizeof(void*) || !BAN::Math::is_power_of_two(alignment))
{
errno = EINVAL;
return -1;
}
return (*memptr = aligned_alloc(alignment, size)) ? 0 : -1;
return EINVAL;
return (*memptr = aligned_alloc(alignment, size)) ? 0 : errno;
}
size_t malloc_usable_size(void* ptr)
{
if (ptr == nullptr)
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)
+35 -4
View File
@@ -1,5 +1,6 @@
#include <BAN/Math.h>
#include <errno.h>
#include <math.h>
#include <stddef.h>
@@ -156,6 +157,36 @@ static T1 nextafter_impl(T1 x, T2 y)
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)
{
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;
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;
return 2.0L / sqrt_pi * sum;
@@ -237,7 +268,7 @@ BAN_FUNC2_TYPE(frexp, int*)
BAN_FUNC2(hypot)
FUNC_EXPR1_RET(ilogb, int, BAN::Math::logb(a))
// 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_RET(llrint, long long, BAN::Math::rint(a))
FUNC_EXPR1_RET(llround, long long, BAN::Math::round(a))
@@ -260,8 +291,8 @@ BAN_FUNC2(remainder)
// remquo
BAN_FUNC1(rint)
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(scalbn, int, BAN::Math::scalbn(a, b))
FUNC_EXPR2_TYPE(scalbln, long, ldexp_impl(a, b))
FUNC_EXPR2_TYPE(scalbn, int, ldexp_impl(a, b))
BAN_FUNC1(sin)
BAN_FUNC1(sinh)
BAN_FUNC1(sqrt)
+58 -48
View File
@@ -28,9 +28,11 @@ static pthread_attr_t s_default_pthread_attr {
.scope = PTHREAD_SCOPE_SYSTEM,
.stackaddr = nullptr,
.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)
{
uthread* uthread = _get_uthread();
@@ -44,6 +46,8 @@ static void _pthread_cancel_handler(int)
__attribute__((constructor))
static void _init_pthread()
{
s_default_pthread_attr.guardsize = getpagesize();
uthread* uthread = _get_uthread();
uthread->id = syscall(SYS_THREAD_GETID);
uthread->attr = s_default_pthread_attr;
@@ -67,9 +71,9 @@ static void _init_pthread()
const char* last_slash = strrchr(buffer, '/');
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';
signal(SIGCANCEL, &_pthread_cancel_handler);
@@ -122,35 +126,18 @@ extern "C" void _pthread_trampoline_cpp(void* arg)
static void free_uthread(uthread* uthread)
{
const auto lock_dynamic_tls =
[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++)
for (size_t i = uthread->master_tls_module_count + 1; i <= uthread->dtv[0]; i++)
{
if (uthread->dtv[i] == 0)
continue;
lock_dynamic_tls();
const size_t size = uthread->dynamic_tls->entries[i].master_size;
unlock_dynamic_tls();
munmap(reinterpret_cast<void*>(uthread->dtv[i]), size);
munmap(
reinterpret_cast<void*>(uthread->dtv[i]),
uthread->dynamic_tls->entries[i].master_size
);
}
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;
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)
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 = {
.self = uthread,
@@ -473,12 +457,21 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric
};
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)
{
ASSERT(uthread->attr.stacksize % 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)
goto pthread_create_error;
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;
}
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;
}
@@ -558,8 +545,26 @@ void pthread_exit(void* value_ptr)
}
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);
}
syscall(SYS_THREAD_EXIT, value_ptr);
ASSERT_NOT_REACHED();
}
@@ -588,10 +593,14 @@ int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
{
init_routine();
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;
}
@@ -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)
{
(void)thread;
(void)policy;
(void)param;
dwarnln("TODO: pthread_getschedparam");
return ENOTSUP;
*policy = thread->attr.schedpolicy;
*param = thread->attr.schedparam;
return 0;
}
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;
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);
if (ret == -1 && errno == ETIMEDOUT)
return ETIMEDOUT;
if (err && err != EAGAIN)
return err;
expected = 0;
}
@@ -1225,8 +1232,8 @@ int pthread_cond_timedwait(pthread_cond_t* __restrict cond, pthread_mutex_t* __r
const int op = FUTEX_WAIT
| (cond->attr.shared ? 0 : FUTEX_PRIVATE)
| (cond->attr.clock == CLOCK_REALTIME ? FUTEX_REALTIME : 0);
if (futex(op, &block.futex, 0, abstime) == -1 && errno == ETIMEDOUT)
ret = ETIMEDOUT;
if (const int err = futex(op, &block.futex, 0, abstime); err != EAGAIN)
ret = err;
}
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_mutex_lock(mutex);
return ret;
}
@@ -1400,6 +1408,8 @@ static void load_dynamic_tls_module(size_t module)
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);
}
+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,8 +57,11 @@ int sem_timedwait(sem_t* __restrict sem, const struct timespec* __restrict absti
}
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;
}
}
}
+24 -26
View File
@@ -355,13 +355,12 @@ int mblen(const char* s, size_t n)
return 0;
if (n == 0)
return -1;
switch (__getlocale(LC_CTYPE))
switch (__getlocale(LC_CTYPE)->encoding)
{
case LOCALE_INVALID:
ASSERT_NOT_REACHED();
case LOCALE_POSIX:
case __ENC_ASCII:
return 1;
case LOCALE_UTF8:
case __ENC_UTF8:
const auto bytes = BAN::UTF8::byte_length(*s);
if (bytes == BAN::UTF8::invalid)
return -1;
@@ -369,6 +368,7 @@ int mblen(const char* s, size_t n)
return -1;
return bytes;
}
ASSERT_NOT_REACHED();
}
@@ -378,15 +378,13 @@ int mbtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n)
if (s == nullptr)
return 0;
switch (__getlocale(LC_CTYPE))
switch (__getlocale(LC_CTYPE)->encoding)
{
case LOCALE_INVALID:
ASSERT_NOT_REACHED();
case LOCALE_POSIX:
case __ENC_ASCII:
if (pwc != nullptr)
*pwc = *s;
return *s ? 1 : 0;
case LOCALE_UTF8:
case __ENC_UTF8:
const auto* us = reinterpret_cast<const unsigned char*>(s);
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;
switch (__getlocale(LC_CTYPE))
switch (__getlocale(LC_CTYPE)->encoding)
{
case LOCALE_INVALID:
ASSERT_NOT_REACHED();
case LOCALE_POSIX:
case __ENC_ASCII:
if (pwcs == nullptr)
written = strlen(s);
else for (; s[written] && written < n; written++)
pwcs[written] = s[written];
break;
case LOCALE_UTF8:
case __ENC_UTF8:
{
const auto* us = reinterpret_cast<const unsigned char*>(s);
for (; *us && (pwcs == nullptr || written < n); written++)
{
@@ -441,6 +438,9 @@ size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n)
us += BAN::UTF8::byte_length(*us);
}
break;
}
default:
ASSERT_NOT_REACHED();
}
if (pwcs != nullptr && written < n)
@@ -454,14 +454,12 @@ int wctomb(char* s, wchar_t wchar)
if (s == nullptr)
return 0;
switch (__getlocale(LC_CTYPE))
switch (__getlocale(LC_CTYPE)->encoding)
{
case locale_t::LOCALE_INVALID:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
case __ENC_ASCII:
*s = wchar;
return wchar ? 1 : 0;
case locale_t::LOCALE_UTF8:
case __ENC_UTF8:
char buffer[5];
if (!BAN::UTF8::from_codepoints(&wchar, 1, buffer))
return -1;
@@ -477,11 +475,9 @@ size_t wcstombs(char* __restrict s, const wchar_t* __restrict pwcs, size_t n)
{
size_t written = 0;
switch (__getlocale(LC_CTYPE))
switch (__getlocale(LC_CTYPE)->encoding)
{
case locale_t::LOCALE_INVALID:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
case __ENC_ASCII:
for (size_t i = 0; pwcs[i] && (s == nullptr || written < n); i++)
{
if (pwcs[i] > 0xFF)
@@ -491,7 +487,7 @@ size_t wcstombs(char* __restrict s, const wchar_t* __restrict pwcs, size_t n)
written++;
}
break;
case locale_t::LOCALE_UTF8:
case __ENC_UTF8:
for (size_t i = 0; pwcs[i] && (s == nullptr || written < n); i++)
{
char buffer[5];
@@ -507,6 +503,8 @@ size_t wcstombs(char* __restrict s, const wchar_t* __restrict pwcs, size_t n)
written += len;
}
break;
default:
ASSERT_NOT_REACHED();
}
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)
{
+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)
{
switch (locale)
switch (locale->encoding)
{
case LOCALE_INVALID:
ASSERT_NOT_REACHED();
case LOCALE_POSIX:
case __ENC_ASCII:
return strcmp(s1, s2);
case LOCALE_UTF8:
case __ENC_UTF8:
{
const unsigned char* u1 = (unsigned char*)s1;
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;
}
}
ASSERT_NOT_REACHED();
}
+20 -3
View File
@@ -1,9 +1,26 @@
#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)
{
(void)buffer;
ASSERT_NOT_REACHED();
// FIXME: system time, child times
*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;
#define DUMP_BACKTRACE 0
#define DUMP_BACKTRACE 1
#define DEMANGLE_BACKTRACE 0
#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)
return 1;
switch (__getlocale(LC_CTYPE))
switch (__getlocale(LC_CTYPE)->encoding)
{
case locale_t::LOCALE_INVALID:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
case __ENC_ASCII:
if (ws > 0x7F)
break;
*s = ws;
return 1;
case locale_t::LOCALE_UTF8:
case __ENC_UTF8:
if (!BAN::UTF8::from_codepoints(&ws, 1, s))
break;
return BAN::UTF8::byte_length(s[0]);
default:
ASSERT_NOT_REACHED();
}
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);
size_t bytes = -1;
switch (locale)
switch (locale->encoding)
{
case locale_t::LOCALE_INVALID:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
case __ENC_ASCII:
bytes = 1;
break;
case locale_t::LOCALE_UTF8:
case __ENC_UTF8:
if (auto b = BAN::UTF8::byte_length(s[0]); b != BAN::UTF8::invalid)
bytes = b;
break;
default:
ASSERT_NOT_REACHED();
}
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;
wchar_t codepoint = WEOF;
switch (locale)
switch (locale->encoding)
{
case locale_t::LOCALE_INVALID:
ASSERT_NOT_REACHED();
case locale_t::LOCALE_POSIX:
case __ENC_ASCII:
codepoint = s[0];
break;
case locale_t::LOCALE_UTF8:
case __ENC_UTF8:
if (auto cp = BAN::UTF8::to_codepoint(s); cp != BAN::UTF8::invalid)
codepoint = cp;
break;
default:
ASSERT_NOT_REACHED();
}
if (codepoint == WEOF)
+26 -33
View File
@@ -152,7 +152,6 @@ struct LoadedElf
ElfNativeProgramHeader tls_header;
ElfNativeDynamic* dynamics;
uint8_t* tls_addr;
size_t tls_module;
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);
}
// do "normal" relocations
// do mandatory relocations
if (elf.rel && elf.relent)
{
for (size_t i = 0; i < elf.relsz / elf.relent; i++)
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++)
handle_tls_relocation(elf, *reinterpret_cast<ElfNativeRelocation*>(elf.rel + i * elf.relent));
}
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++)
handle_tls_relocation(elf, *reinterpret_cast<ElfNativeRelocationA*>(elf.rela + i * elf.relaent));
}
// do jumprel relocations
if (elf.jmprel && elf.pltrelsz)
@@ -1226,7 +1225,6 @@ static MasterTLS initialize_tls_stage1()
size_t max_align = alignof(uthread);
size_t tls_m_offset = 0;
size_t tls_m_size = 0;
size_t module_count = 0;
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);
tls_m_offset = round(tls_m_offset + tls_header.p_memsz, tls_header.p_align);
tls_m_size = tls_header.p_memsz;
module_count++;
}
@@ -1246,7 +1243,7 @@ static MasterTLS initialize_tls_stage1()
if (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)
master_tls_size += max_align - rem;
@@ -1268,7 +1265,8 @@ static MasterTLS initialize_tls_stage1()
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;
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);
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_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++)
{
const auto& tls_header = s_loaded_files[i].tls_header;
if (tls_header.p_type != PT_TLS)
continue;
auto& elf = s_loaded_files[i];
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);
uint8_t* master_addr = master_tls.addr + master_tls.size - s_loaded_files[i].tls_offset;
memcpy(master_addr, reinterpret_cast<void*>(tls_header.p_vaddr), tls_header.p_filesz);
}
}
@@ -1330,16 +1325,14 @@ static void initialize_tls_stage2(MasterTLS master_tls)
{
allocate_dynamic_tls();
initialize_tls_memory();
const size_t tls_size = master_tls.size + sizeof(uthread);
initialize_master_tls_data(master_tls);
uint8_t* tls_addr;
{
const sys_mmap_t mmap_args {
.addr = nullptr,
.len = tls_size,
.len = master_tls.size + sizeof(uthread),
.prot = PROT_READ | PROT_WRITE,
.flags = MAP_ANONYMOUS | MAP_PRIVATE,
.fildes = -1,
@@ -1348,14 +1341,11 @@ static void initialize_tls_stage2(MasterTLS master_tls)
const auto ret = syscall(SYS_MMAP, &mmap_args);
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);
}
memcpy(tls_addr, master_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.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++)
{
const auto& elf = s_loaded_files[i];
if (elf.tls_addr == nullptr)
if (elf.tls_header.p_type != PT_TLS)
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__)
@@ -1504,6 +1496,8 @@ static void register_fini_funcs(LoadedElf& elf, bool is_main_elf)
static void load_dynamic_tls(LoadedElf& elf)
{
uint8_t* tls_addr;
{
const sys_mmap_t mmap_args {
.addr = nullptr,
@@ -1517,12 +1511,11 @@ static void load_dynamic_tls(LoadedElf& elf)
const auto ret = syscall(SYS_MMAP, &mmap_args);
if (ret < 0)
print_error_and_exit("failed to allocate dynamic TLS", 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);
tls_addr = reinterpret_cast<uint8_t*>(ret);
}
memcpy(tls_addr, reinterpret_cast<void*>(elf.tls_header.p_vaddr), elf.tls_header.p_filesz);
int expected = 0;
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++] = {
.master_addr = elf.tls_addr,
.master_addr = tls_addr,
.master_size = elf.tls_header.p_memsz,
};