Compare commits
47
Commits
3148c28c3d
...
328771ae29
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
328771ae29 | ||
|
|
0b53fba991 | ||
|
|
0d390e2246 | ||
|
|
a3b7a758eb | ||
|
|
d46d7a5123 | ||
|
|
b611c3fe48 | ||
|
|
8c6e402ee8 | ||
|
|
bd5be982e9 | ||
|
|
33f941f2fd | ||
|
|
8368dec30b | ||
|
|
7f25350c62 | ||
|
|
64523b6c70 | ||
|
|
a9cf0134b7 | ||
|
|
2e8239fefa | ||
|
|
f2bf406db7 | ||
|
|
63a8f40e67 | ||
|
|
2ddee7016e | ||
|
|
bc622c8b51 | ||
|
|
6ebd3a8aca | ||
|
|
96e5779182 | ||
|
|
02f05436fc | ||
|
|
51251e492e | ||
|
|
20e36125c8 | ||
|
|
19c228362b | ||
|
|
cf9a495f1d | ||
|
|
5329ec5912 | ||
|
|
edc95e1c09 | ||
|
|
46e2d665e9 | ||
|
|
0242a4f968 | ||
|
|
390a7674b1 | ||
|
|
f96f2b4cac | ||
|
|
51b9dcebbc | ||
|
|
583c2437b4 | ||
|
|
efb25e5666 | ||
|
|
f0e95ffe48 | ||
|
|
511ab7e99c | ||
|
|
4df58c5155 | ||
|
|
f6e27e5f05 | ||
|
|
87006e277f | ||
|
|
2c340c5532 | ||
|
|
f6b91578ae | ||
|
|
73a95bd725 | ||
|
|
130c4f681c | ||
|
|
e03a26cf01 | ||
|
|
2a3eca5b36 | ||
|
|
658e74b507 | ||
|
|
9bdf60bb88 |
+12
-31
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 };
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {};
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,4 +1,3 @@
|
||||
#include <kernel/Lock/SpinLockAsMutex.h>
|
||||
#include <kernel/Networking/ARPTable.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {};
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
Executable
+19
@@ -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;
|
||||
Executable
+20
@@ -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 = '\\';
|
||||
Executable
+21
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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 +0,0 @@
|
||||
../../../toolchain/gcc-15.2.0.patch
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../toolchain/gcc-15.3.0.patch
|
||||
+4
-7
@@ -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__ */
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
@@ -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.
|
||||
;;
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user