Compare commits

..

19 Commits

Author SHA1 Message Date
f77aa65dc5 Kernel: Cleanup accessing userspace memory
Instead of doing page validiation and loading manually we just do simple
memcpy and handle the possible page faults
2026-04-02 16:36:33 +03:00
9589b5984d Kernel: Move USERSPACE_END to lower half
This allows calculating distance to USERSPACE_END from lower half
address
2026-04-02 16:34:47 +03:00
32806a5af3 LibC: Allow "t" in stdio mode 2026-04-02 15:44:50 +03:00
876fbe3d7c LibC: Fix sem_{,timed}wait 2026-04-02 15:43:34 +03:00
c1b8f5e475 LibC: Add and cleanup network definitions 2026-04-02 15:42:00 +03:00
cf31ea9cbe LibC: Add _SC_PHYS_PAGES and _SC_AVPHYS_PAGES 2026-04-02 15:41:26 +03:00
7e6b8c93b4 LibC: Implement strsep 2026-04-02 15:40:23 +03:00
dd2bbe4588 LibC: Implement sched_getcpu 2026-04-02 15:39:36 +03:00
e01e35713b LibC: Allow including assert.h multiple times
Some shit seems to depend on this
2026-04-02 15:38:06 +03:00
82d5d9ba58 LibC: Write memchr, memcmp and strlen with sse 2026-04-02 15:35:03 +03:00
d168492462 WindowServer: bind volume up/down to volume control 2026-04-02 15:24:02 +03:00
6f2e8320a9 TaskBar: Show current volume level 2026-04-02 15:22:42 +03:00
bf4831f468 AudioServer: Add support for volume control 2026-04-02 15:21:38 +03:00
5647cf24d2 Kernel: Implement volume control to audio drivers 2026-04-02 15:14:27 +03:00
85f61aded5 BAN: Use builtins for math overflow 2026-04-02 14:49:12 +03:00
21639071c2 kill: Allow killing with process name 2026-04-02 05:02:05 +03:00
68506a789a Kernel: Add support for volume control keys 2026-04-02 05:02:05 +03:00
d9ca25b796 LibC: Add FNM_CASEFOLD and FNM_IGNORECASE
These are part of POSIX issue 8
2026-03-25 04:27:00 +02:00
e9c81477d7 BAN/LibC: Implement remainder
This is basically just fmod but with fprem1 instead of fprem
2026-03-25 01:06:45 +02:00
46 changed files with 937 additions and 421 deletions

View File

@@ -6,19 +6,6 @@
#include <float.h>
// This is ugly but my clangd does not like including
// intrinsic headers at all
#if !defined(__SSE__) || !defined(__SSE2__)
#pragma GCC push_options
#ifndef __SSE__
#pragma GCC target("sse")
#endif
#ifndef __SSE2__
#pragma GCC target("sse2")
#endif
#define BAN_MATH_POP_OPTIONS
#endif
namespace BAN::Math
{
@@ -49,12 +36,11 @@ namespace BAN::Math
template<integral T>
inline constexpr T gcd(T a, T b)
{
T t;
while (b)
{
t = b;
T temp = b;
b = a % b;
a = t;
a = temp;
}
return a;
}
@@ -79,25 +65,20 @@ namespace BAN::Math
return (x & (x - 1)) == 0;
}
template<BAN::integral T>
static constexpr bool will_multiplication_overflow(T a, T b)
template<integral T>
__attribute__((always_inline))
inline constexpr bool will_multiplication_overflow(T a, T b)
{
if (a == 0 || b == 0)
return false;
if ((a > 0) == (b > 0))
return a > BAN::numeric_limits<T>::max() / b;
else
return a < BAN::numeric_limits<T>::min() / b;
T dummy;
return __builtin_mul_overflow(a, b, &dummy);
}
template<BAN::integral T>
static constexpr bool will_addition_overflow(T a, T b)
template<integral T>
__attribute__((always_inline))
inline constexpr bool will_addition_overflow(T a, T b)
{
if (a > 0 && b > 0)
return a > BAN::numeric_limits<T>::max() - b;
if (a < 0 && b < 0)
return a < BAN::numeric_limits<T>::min() - b;
return false;
T dummy;
return __builtin_add_overflow(a, b, &dummy);
}
template<typename T>
@@ -111,6 +92,19 @@ namespace BAN::Math
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
}
// This is ugly but my clangd does not like including
// intrinsic headers at all
#if !defined(__SSE__) || !defined(__SSE2__)
#pragma GCC push_options
#ifndef __SSE__
#pragma GCC target("sse")
#endif
#ifndef __SSE2__
#pragma GCC target("sse2")
#endif
#define BAN_MATH_POP_OPTIONS
#endif
template<floating_point T>
inline constexpr T floor(T x)
{
@@ -172,7 +166,23 @@ namespace BAN::Math
"jne 1b;"
: "+t"(a)
: "u"(b)
: "ax"
: "ax", "cc"
);
return a;
}
template<floating_point T>
inline constexpr T remainder(T a, T b)
{
asm(
"1:"
"fprem1;"
"fnstsw %%ax;"
"testb $4, %%ah;"
"jne 1b;"
: "+t"(a)
: "u"(b)
: "ax", "cc"
);
return a;
}
@@ -447,9 +457,9 @@ namespace BAN::Math
return sqrt<T>(x * x + y * y);
}
}
#ifdef BAN_MATH_POP_OPTIONS
#undef BAN_MATH_POP_OPTIONS
#pragma GCC pop_options
#endif
}

Binary file not shown.

View File

@@ -139,6 +139,7 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
arch/x86_64/Signal.S
arch/x86_64/Syscall.S
arch/x86_64/Thread.S
arch/x86_64/User.S
arch/x86_64/Yield.S
)
elseif("${BANAN_ARCH}" STREQUAL "i686")
@@ -150,6 +151,7 @@ elseif("${BANAN_ARCH}" STREQUAL "i686")
arch/i686/Signal.S
arch/i686/Syscall.S
arch/i686/Thread.S
arch/i686/User.S
arch/i686/Yield.S
)
else()

54
kernel/arch/i686/User.S Normal file
View File

@@ -0,0 +1,54 @@
# bool safe_user_memcpy(void*, const void*, size_t)
.global safe_user_memcpy
.global safe_user_memcpy_end
.global safe_user_memcpy_fault
safe_user_memcpy:
xorl %eax, %eax
xchgl 4(%esp), %edi
xchgl 8(%esp), %esi
movl 12(%esp), %ecx
movl %edi, %edx
rep movsb
movl 4(%esp), %edi
movl 8(%esp), %esi
incl %eax
safe_user_memcpy_fault:
ret
safe_user_memcpy_end:
# bool safe_user_strncpy(void*, const void*, size_t)
.global safe_user_strncpy
.global safe_user_strncpy_end
.global safe_user_strncpy_fault
safe_user_strncpy:
xchgl 4(%esp), %edi
xchgl 8(%esp), %esi
movl 12(%esp), %ecx
testl %ecx, %ecx
jz safe_user_strncpy_fault
.safe_user_strncpy_loop:
movb (%esi), %al
movb %al, (%edi)
testb %al, %al
jz .safe_user_strncpy_done
incl %edi
incl %esi
decl %ecx
jnz .safe_user_strncpy_loop
safe_user_strncpy_fault:
xorl %eax, %eax
jmp .safe_user_strncpy_return
.safe_user_strncpy_done:
movl $1, %eax
.safe_user_strncpy_return:
movl 4(%esp), %edi
movl 8(%esp), %esi
ret
safe_user_strncpy_end:

View File

@@ -866,7 +866,7 @@ namespace Kernel
last_address -= rem;
ASSERT(is_canonical(first_address));
ASSERT(is_canonical(last_address));
ASSERT(is_canonical(last_address - 1));
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
const vaddr_t uc_vaddr_end = uncanonicalize(last_address);
@@ -948,7 +948,7 @@ namespace Kernel
last_address -= rem;
ASSERT(is_canonical(first_address));
ASSERT(is_canonical(last_address));
ASSERT(is_canonical(last_address - 1));
SpinLockGuard _(m_lock);

87
kernel/arch/x86_64/User.S Normal file
View File

@@ -0,0 +1,87 @@
# bool safe_user_memcpy(void*, const void*, size_t)
.global safe_user_memcpy
.global safe_user_memcpy_end
.global safe_user_memcpy_fault
safe_user_memcpy:
xorq %rax, %rax
movq %rdx, %rcx
rep movsb
incq %rax
safe_user_memcpy_fault:
ret
safe_user_memcpy_end:
# bool safe_user_strncpy(void*, const void*, size_t)
.global safe_user_strncpy
.global safe_user_strncpy_end
.global safe_user_strncpy_fault
safe_user_strncpy:
movq %rdx, %rcx
testq %rcx, %rcx
jz safe_user_strncpy_fault
.safe_user_strncpy_align_loop:
testb $0x7, %sil
jz .safe_user_strncpy_align_done
movb (%rsi), %al
movb %al, (%rdi)
testb %al, %al
jz .safe_user_strncpy_done
incq %rdi
incq %rsi
decq %rcx
jnz .safe_user_strncpy_align_loop
jmp safe_user_strncpy_fault
.safe_user_strncpy_align_done:
movq $0x0101010101010101, %r8
movq $0x8080808080808080, %r9
.safe_user_strncpy_qword_loop:
cmpq $8, %rcx
jb .safe_user_strncpy_qword_done
movq (%rsi), %rax
movq %rax, %r10
movq %rax, %r11
# https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
subq %r8, %r10
notq %r11
andq %r11, %r10
andq %r9, %r10
jnz .safe_user_strncpy_byte_loop
movq %rax, (%rdi)
addq $8, %rdi
addq $8, %rsi
subq $8, %rcx
jnz .safe_user_strncpy_qword_loop
jmp safe_user_strncpy_fault
.safe_user_strncpy_qword_done:
testq %rcx, %rcx
jz safe_user_strncpy_fault
.safe_user_strncpy_byte_loop:
movb (%rsi), %al
movb %al, (%rdi)
testb %al, %al
jz .safe_user_strncpy_done
incq %rdi
incq %rsi
decq %rcx
jnz .safe_user_strncpy_byte_loop
safe_user_strncpy_fault:
xorq %rax, %rax
ret
.safe_user_strncpy_done:
movb $1, %al
ret
safe_user_strncpy_end:

View File

@@ -6,7 +6,7 @@
namespace Kernel
{
class AC97AudioController : public AudioController, public Interruptable
class AC97AudioController final : public AudioController, public Interruptable
{
public:
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
@@ -23,11 +23,15 @@ namespace Kernel
uint32_t get_current_pin() const override { return 0; }
BAN::ErrorOr<void> set_current_pin(uint32_t pin) override { if (pin != 0) return BAN::Error::from_errno(EINVAL); return {}; }
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
private:
AC97AudioController(PCI::Device& pci_device)
: m_pci_device(pci_device)
{ }
uint32_t get_volume_data() const;
BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> initialize_bld();
BAN::ErrorOr<void> initialize_interrupts();

View File

@@ -4,6 +4,8 @@
#include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/PCI.h>
#include <sys/ioctl.h>
namespace Kernel
{
@@ -28,6 +30,8 @@ namespace Kernel
virtual uint32_t get_current_pin() const = 0;
virtual BAN::ErrorOr<void> set_current_pin(uint32_t) = 0;
virtual BAN::ErrorOr<void> set_volume_mdB(int32_t) = 0;
bool can_read_impl() const override { return false; }
bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return !m_sample_data->full(); }
bool has_error_impl() const override { return false; }
@@ -44,6 +48,8 @@ namespace Kernel
static constexpr size_t m_sample_data_capacity = 1 << 20;
BAN::UniqPtr<ByteRingBuffer> m_sample_data;
snd_volume_info m_volume_info {};
private:
const dev_t m_rdev;
char m_name[10] {};

View File

@@ -8,7 +8,7 @@ namespace Kernel
class HDAudioController;
class HDAudioFunctionGroup : public AudioController
class HDAudioFunctionGroup final : public AudioController
{
public:
static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&);
@@ -24,6 +24,8 @@ namespace Kernel
uint32_t get_current_pin() const override;
BAN::ErrorOr<void> set_current_pin(uint32_t) override;
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
void handle_new_data() override;
private:
@@ -46,7 +48,6 @@ namespace Kernel
BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path);
uint16_t get_format_data() const;
uint16_t get_volume_data() const;
size_t bdl_offset() const;

View File

@@ -55,6 +55,16 @@ namespace Kernel::HDAudio
} pin_complex;
};
struct Amplifier
{
uint8_t offset;
uint8_t num_steps;
uint8_t step_size;
bool mute;
};
BAN::Optional<Amplifier> output_amplifier;
BAN::Vector<uint16_t> connections;
};

View File

@@ -4,7 +4,7 @@
#if ARCH(x86_64)
#define KERNEL_OFFSET 0xFFFFFFFF80000000
#define USERSPACE_END 0xFFFF800000000000
#define USERSPACE_END 0x800000000000
#elif ARCH(i686)
#define KERNEL_OFFSET 0xC0000000
#define USERSPACE_END 0xC0000000

View File

@@ -137,8 +137,27 @@ namespace Kernel
// Reset mixer to default values
m_mixer->write16(AudioMixerRegister::Reset, 0);
// Master volume 100%, no mute
m_mixer->write16(AudioMixerRegister::MasterVolume, 0x0000);
// Master volumes
m_mixer->write16(AudioMixerRegister::MasterVolume, 0x2020);
if (m_mixer->read16(AudioMixerRegister::MasterVolume) == 0x2020)
{
m_volume_info = {
.min_mdB = -94500,
.max_mdB = 0,
.step_mdB = 1500,
.mdB = 0,
};
}
else
{
m_volume_info = {
.min_mdB = -46500,
.max_mdB = 0,
.step_mdB = 1500,
.mdB = 0,
};
}
m_mixer->write16(AudioMixerRegister::MasterVolume, get_volume_data());
// PCM output volume left/right +0 db, no mute
m_mixer->write16(AudioMixerRegister::PCMOutVolume, 0x0808);
@@ -187,6 +206,19 @@ namespace Kernel
return {};
}
uint32_t AC97AudioController::get_volume_data() const
{
const uint32_t steps = (-m_volume_info.mdB + m_volume_info.step_mdB / 2) / m_volume_info.step_mdB;
return (steps << 8) | steps;
}
BAN::ErrorOr<void> AC97AudioController::set_volume_mdB(int32_t mdB)
{
m_volume_info.mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
m_mixer->write16(AudioMixerRegister::MasterVolume, get_volume_data());
return {};
}
void AC97AudioController::handle_new_data()
{
ASSERT(m_spinlock.current_processor_has_lock());

View File

@@ -105,6 +105,12 @@ namespace Kernel
case SND_SET_PIN:
TRY(set_current_pin(*static_cast<uint32_t*>(arg)));
return 0;
case SND_GET_VOLUME_INFO:
*static_cast<snd_volume_info*>(arg) = m_volume_info;
return 0;
case SND_SET_VOLUME_MDB:
TRY(set_volume_mdB(*static_cast<int32_t*>(arg)));
return 0;
}
return CharacterDevice::ioctl_impl(cmd, arg);

View File

@@ -136,6 +136,37 @@ namespace Kernel
return BAN::Error::from_errno(ENOTSUP);
}
BAN::ErrorOr<void> HDAudioFunctionGroup::set_volume_mdB(int32_t mdB)
{
mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
const auto& path = m_output_paths[m_output_path_index];
for (size_t i = 0; i < path.size(); i++)
{
if (!path[i]->output_amplifier.has_value())
continue;
const int32_t step_round = (mdB >= 0)
? +m_volume_info.step_mdB / 2
: -m_volume_info.step_mdB / 2;
const uint32_t step = (mdB + step_round) / m_volume_info.step_mdB + path[i]->output_amplifier->offset;
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
TRY(m_controller->send_command({
.data = static_cast<uint8_t>(volume & 0xFF),
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
.node_index = path[i]->id,
.codec_address = m_cid,
}));
break;
}
m_volume_info.mdB = mdB;
return {};
}
size_t HDAudioFunctionGroup::bdl_offset() const
{
const size_t bdl_entry_bytes = m_bdl_entry_sample_frames * get_channels() * sizeof(uint16_t);
@@ -291,13 +322,6 @@ namespace Kernel
return 0b0'0'000'000'0'001'0001;
}
uint16_t HDAudioFunctionGroup::get_volume_data() const
{
// TODO: don't hardcode this
// left and right output, no mute, max gain
return 0b1'0'1'1'0000'0'1111111;
}
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
{
ASSERT(index < m_output_paths.size());
@@ -318,7 +342,6 @@ namespace Kernel
}
const auto format = get_format_data();
const auto volume = get_volume_data();
for (size_t i = 0; i < path.size(); i++)
{
@@ -347,13 +370,17 @@ namespace Kernel
}));
}
// set volume
// set volume to 0 dB, no mute
if (path[i]->output_amplifier.has_value())
{
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | path[i]->output_amplifier->offset;
TRY(m_controller->send_command({
.data = static_cast<uint8_t>(volume & 0xFF),
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
.node_index = path[i]->id,
.codec_address = m_cid,
}));
}
switch (path[i]->type)
{
@@ -398,6 +425,41 @@ namespace Kernel
}
}
// update volume info to this path
m_volume_info.min_mdB = 0;
m_volume_info.max_mdB = 0;
m_volume_info.step_mdB = 0;
for (size_t i = 0; i < path.size(); i++)
{
if (!path[i]->output_amplifier.has_value())
continue;
const auto& amp = path[i]->output_amplifier.value();
const int32_t step_mdB = amp.step_size * 250;
m_volume_info.step_mdB = step_mdB;
m_volume_info.min_mdB = -amp.offset * step_mdB;
m_volume_info.max_mdB = (amp.num_steps - amp.offset) * step_mdB;
m_volume_info.mdB = BAN::Math::clamp(m_volume_info.mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
const int32_t step_round = (m_volume_info.mdB >= 0)
? +step_mdB / 2
: -step_mdB / 2;
const uint32_t step = (m_volume_info.mdB + step_round) / step_mdB + amp.offset;
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
TRY(m_controller->send_command({
.data = static_cast<uint8_t>(volume & 0xFF),
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
.node_index = path[i]->id,
.codec_address = m_cid,
}));
break;
}
if (m_volume_info.min_mdB == 0 && m_volume_info.max_mdB == 0)
m_volume_info.mdB = 0;
return {};
}

View File

@@ -319,6 +319,20 @@ namespace Kernel
};
}
if (const uint32_t out_amp_cap = send_command_or_zero(0xF00, 0x12))
{
const uint8_t offset = (out_amp_cap >> 0) & 0x7F;
const uint8_t num_steps = (out_amp_cap >> 8) & 0x7F;
const uint8_t step_size = (out_amp_cap >> 16) & 0x7F;
const bool mute = (out_amp_cap >> 31);
result.output_amplifier = HDAudio::AFGWidget::Amplifier {
.offset = offset,
.num_steps = num_steps,
.step_size = step_size,
.mute = mute,
};
}
const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E);
const uint8_t conn_width = (connection_info & 0x80) ? 2 : 1;
const uint8_t conn_count = connection_info & 0x3F;

View File

@@ -164,6 +164,33 @@ namespace Kernel
"Unkown Exception 0x1F",
};
extern "C" uint8_t safe_user_memcpy[];
extern "C" uint8_t safe_user_memcpy_end[];
extern "C" uint8_t safe_user_memcpy_fault[];
extern "C" uint8_t safe_user_strncpy[];
extern "C" uint8_t safe_user_strncpy_end[];
extern "C" uint8_t safe_user_strncpy_fault[];
struct safe_user_page_fault
{
const uint8_t* ip_start;
const uint8_t* ip_end;
const uint8_t* ip_fault;
};
static constexpr safe_user_page_fault s_safe_user_page_faults[] {
{
.ip_start = safe_user_memcpy,
.ip_end = safe_user_memcpy_end,
.ip_fault = safe_user_memcpy_fault,
},
{
.ip_start = safe_user_strncpy,
.ip_end = safe_user_strncpy_end,
.ip_fault = safe_user_strncpy_fault,
},
};
extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack* interrupt_stack, const Registers* regs)
{
if (g_paniced)
@@ -201,6 +228,15 @@ namespace Kernel
if (result.value())
return;
const uint8_t* ip = reinterpret_cast<const uint8_t*>(interrupt_stack->ip);
for (const auto& safe_user : s_safe_user_page_faults)
{
if (ip < safe_user.ip_start || ip >= safe_user.ip_end)
continue;
interrupt_stack->ip = reinterpret_cast<vaddr_t>(safe_user.ip_fault);
return;
}
break;
}
case ISR::DeviceNotAvailable:

View File

@@ -136,6 +136,9 @@ namespace Kernel::Input
m_scancode_to_keycode_extended[0x49] = keycode_function(18);
m_scancode_to_keycode_extended[0x51] = keycode_function(19);
m_scancode_to_keycode_normal[0x46] = keycode_function(20);
m_scancode_to_keycode_extended[0x20] = keycode_function(21);
m_scancode_to_keycode_extended[0x2E] = keycode_function(22);
m_scancode_to_keycode_extended[0x30] = keycode_function(23);
// Arrow keys
m_scancode_to_keycode_extended[0x48] = keycode_normal(5, 0);
@@ -246,6 +249,9 @@ namespace Kernel::Input
m_scancode_to_keycode_extended[0x7D] = keycode_function(18);
m_scancode_to_keycode_extended[0x7A] = keycode_function(19);
m_scancode_to_keycode_normal[0x7E] = keycode_function(20);
m_scancode_to_keycode_extended[0x23] = keycode_function(21);
m_scancode_to_keycode_extended[0x21] = keycode_function(22);
m_scancode_to_keycode_extended[0x32] = keycode_function(23);
// Arrow keys
m_scancode_to_keycode_extended[0x75] = keycode_normal(5, 0);
@@ -356,6 +362,9 @@ namespace Kernel::Input
m_scancode_to_keycode_normal[0x6F] = keycode_function(18);
m_scancode_to_keycode_normal[0x6D] = keycode_function(19);
m_scancode_to_keycode_normal[0x5F] = keycode_function(20);
m_scancode_to_keycode_normal[0x9C] = keycode_function(21);
m_scancode_to_keycode_normal[0x9D] = keycode_function(22);
m_scancode_to_keycode_normal[0x95] = keycode_function(23);
// Arrow keys
m_scancode_to_keycode_normal[0x63] = keycode_normal(5, 0);

View File

@@ -3887,237 +3887,45 @@ namespace Kernel
return region->allocate_page_containing(address, wants_write);
}
// TODO: The following 3 functions could be simplified into one generic helper function
extern "C" bool safe_user_memcpy(void*, const void*, size_t);
extern "C" bool safe_user_strncpy(void*, const void*, size_t);
static inline bool is_valid_user_address(const void* user_addr, size_t size)
{
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
if (BAN::Math::will_addition_overflow<vaddr_t>(user_vaddr, size))
return false;
if (user_vaddr + size > USERSPACE_END)
return false;
return true;
}
BAN::ErrorOr<void> Process::read_from_user(const void* user_addr, void* out, size_t size)
{
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
auto* out_u8 = static_cast<uint8_t*>(out);
size_t ncopied = 0;
{
RWLockRDGuard _(m_memory_region_lock);
const size_t first_index = find_mapped_region(user_vaddr);
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
{
auto& region = m_mapped_regions[i];
if (!region->contains(user_vaddr + ncopied))
if (!is_valid_user_address(user_addr, size))
return BAN::Error::from_errno(EFAULT);
if (!safe_user_memcpy(out, user_addr, size))
return BAN::Error::from_errno(EFAULT);
const size_t ncopy = BAN::Math::min<size_t>(
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
size - ncopied
);
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
for (size_t p = 0; p < page_count; p++)
{
const auto flags = PageTable::UserSupervisor | PageTable::Present;
if ((m_page_table->get_page_flags(page_base + p * PAGE_SIZE) & flags) != flags)
goto read_from_user_with_allocation;
}
memcpy(out_u8 + ncopied, reinterpret_cast<void*>(user_vaddr + ncopied), ncopy);
ncopied += ncopy;
}
if (ncopied >= size)
return {};
if (ncopied > 0)
return BAN::Error::from_errno(EFAULT);
}
read_from_user_with_allocation:
RWLockWRGuard _(m_memory_region_lock);
const size_t first_index = find_mapped_region(user_vaddr + ncopied);
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
{
auto& region = m_mapped_regions[i];
if (!region->contains(user_vaddr + ncopied))
return BAN::Error::from_errno(EFAULT);
const size_t ncopy = BAN::Math::min<size_t>(
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
size - ncopied
);
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
for (size_t p = 0; p < page_count; p++)
{
const auto flags = PageTable::UserSupervisor | PageTable::Present;
if ((m_page_table->get_page_flags(page_base + p * PAGE_SIZE) & flags) == flags)
continue;
if (!TRY(region->allocate_page_containing(page_base + p * PAGE_SIZE, false)))
return BAN::Error::from_errno(EFAULT);
}
memcpy(out_u8 + ncopied, reinterpret_cast<void*>(user_vaddr + ncopied), ncopy);
ncopied += ncopy;
}
if (ncopied >= size)
return {};
return BAN::Error::from_errno(EFAULT);
}
BAN::ErrorOr<void> Process::read_string_from_user(const char* user_addr, char* out, size_t max_size)
{
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
size_t ncopied = 0;
{
RWLockRDGuard _(m_memory_region_lock);
const size_t first_index = find_mapped_region(user_vaddr);
for (size_t i = first_index; ncopied < max_size && i < m_mapped_regions.size(); i++)
{
auto& region = m_mapped_regions[i];
if (!region->contains(user_vaddr + ncopied))
max_size = BAN::Math::min<size_t>(max_size, USERSPACE_END - reinterpret_cast<vaddr_t>(user_addr));
if (!is_valid_user_address(user_addr, max_size))
return BAN::Error::from_errno(EFAULT);
if (!safe_user_strncpy(out, user_addr, max_size))
return BAN::Error::from_errno(EFAULT);
vaddr_t last_page = 0;
for (; ncopied < max_size; ncopied++)
{
const vaddr_t curr_page = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
if (curr_page != last_page)
{
const auto flags = PageTable::UserSupervisor | PageTable::Present;
if ((m_page_table->get_page_flags(curr_page) & flags) != flags)
goto read_string_from_user_with_allocation;
}
out[ncopied] = user_addr[ncopied];
if (out[ncopied] == '\0')
return {};
last_page = curr_page;
}
}
if (ncopied >= max_size)
return BAN::Error::from_errno(ENAMETOOLONG);
if (ncopied > 0)
return BAN::Error::from_errno(EFAULT);
}
read_string_from_user_with_allocation:
RWLockWRGuard _(m_memory_region_lock);
const size_t first_index = find_mapped_region(user_vaddr + ncopied);
for (size_t i = first_index; ncopied < max_size && i < m_mapped_regions.size(); i++)
{
auto& region = m_mapped_regions[i];
if (!region->contains(user_vaddr + ncopied))
return BAN::Error::from_errno(EFAULT);
vaddr_t last_page = 0;
for (; ncopied < max_size; ncopied++)
{
const vaddr_t curr_page = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
if (curr_page != last_page)
{
const auto flags = PageTable::UserSupervisor | PageTable::Present;
if ((m_page_table->get_page_flags(curr_page) & flags) == flags)
;
else if (!TRY(region->allocate_page_containing(curr_page, false)))
return BAN::Error::from_errno(EFAULT);
}
out[ncopied] = user_addr[ncopied];
if (out[ncopied] == '\0')
return {};
last_page = curr_page;
}
}
if (ncopied >= max_size)
return BAN::Error::from_errno(ENAMETOOLONG);
return BAN::Error::from_errno(EFAULT);
}
BAN::ErrorOr<void> Process::write_to_user(void* user_addr, const void* in, size_t size)
{
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
const auto* in_u8 = static_cast<const uint8_t*>(in);
size_t ncopied = 0;
{
RWLockRDGuard _(m_memory_region_lock);
const size_t first_index = find_mapped_region(user_vaddr);
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
{
auto& region = m_mapped_regions[i];
if (!region->contains(user_vaddr + ncopied))
if (!is_valid_user_address(user_addr, size))
return BAN::Error::from_errno(EFAULT);
if (!safe_user_memcpy(user_addr, in, size))
return BAN::Error::from_errno(EFAULT);
const size_t ncopy = BAN::Math::min<size_t>(
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
size - ncopied
);
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
for (size_t i = 0; i < page_count; i++)
{
const auto flags = PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present;
if ((m_page_table->get_page_flags(page_base + i * PAGE_SIZE) & flags) != flags)
goto write_to_user_with_allocation;
}
memcpy(reinterpret_cast<void*>(user_vaddr + ncopied), in_u8 + ncopied, ncopy);
ncopied += ncopy;
}
if (ncopied >= size)
return {};
if (ncopied > 0)
return BAN::Error::from_errno(EFAULT);
}
write_to_user_with_allocation:
RWLockWRGuard _(m_memory_region_lock);
const size_t first_index = find_mapped_region(user_vaddr + ncopied);
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
{
auto& region = m_mapped_regions[i];
if (!region->contains(user_vaddr + ncopied))
return BAN::Error::from_errno(EFAULT);
const size_t ncopy = BAN::Math::min<size_t>(
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
size - ncopied
);
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
for (size_t p = 0; p < page_count; p++)
{
const auto flags = PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present;
if ((m_page_table->get_page_flags(page_base + p * PAGE_SIZE) & flags) == flags)
continue;
if (!TRY(region->allocate_page_containing(page_base + p * PAGE_SIZE, true)))
return BAN::Error::from_errno(EFAULT);
}
memcpy(reinterpret_cast<void*>(user_vaddr + ncopied), in_u8 + ncopied, ncopy);
ncopied += ncopy;
}
if (ncopied >= size)
return {};
return BAN::Error::from_errno(EFAULT);
}
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)

View File

@@ -342,6 +342,9 @@ namespace Kernel
s_scancode_to_keycode[0x4B] = keycode_function(18);
s_scancode_to_keycode[0x4E] = keycode_function(19);
s_scancode_to_keycode[0x47] = keycode_function(20);
s_scancode_to_keycode[0x7F] = keycode_function(21);
s_scancode_to_keycode[0x81] = keycode_function(22);
s_scancode_to_keycode[0x80] = keycode_function(23);
s_scancode_to_keycode[0x53] = keycode_numpad(0, 0);
s_scancode_to_keycode[0x54] = keycode_numpad(0, 1);

View File

@@ -145,7 +145,7 @@ namespace LibAudio
LibAudio::Packet packet {
.type = LibAudio::Packet::Notify,
.parameter = 0,
.parameter = {},
};
send(m_server_fd, &packet, sizeof(packet), 0);

View File

@@ -40,6 +40,14 @@ namespace LibAudio
SetPin, // parameter: pin number
// response: nothing
// set the active pin of the current device
GetVolume, // parameter: ignored
// response: 10 * volume percentage (uint32_t)
// get the volume of the current device
SetVolume, // parameter: 10 * volume percentage (uint32_t)
// response: nothing
// set the volume of the current device
} type;
uint64_t parameter;

View File

@@ -1,35 +1,3 @@
.global memchr
memchr:
xchgl 4(%esp), %edi
movl 8(%esp), %eax
movl 12(%esp), %ecx
movl $1, %edx
cmpl $1, %ecx # clear ZF if count is zero
repne scasb
cmovel %edi, %edx
leal -1(%edx), %eax
movl 4(%esp), %edi
ret
.global memcmp
memcmp:
xchgl 4(%esp), %edi
xchgl 8(%esp), %esi
movl 12(%esp), %ecx
testl %ecx, %ecx # set ZF if count is zero
repe cmpsb
jne .memcmp_not_equal
xorl %eax, %eax
jmp .memcmp_done
.memcmp_not_equal:
movzbl -1(%edi), %eax
movzbl -1(%esi), %ecx
subl %ecx, %eax
.memcmp_done:
movl 4(%esp), %edi
movl 8(%esp), %esi
ret
.global memcpy
memcpy:
xchgl 4(%esp), %edi
@@ -74,14 +42,3 @@ memset:
movl 4(%esp), %edi
movl %edx, %eax
ret
.global strlen
strlen:
xchgl 4(%esp), %edi
xorb %al, %al
movl $-1, %ecx
repne scasb
movl 4(%esp), %edi
movl $-2, %eax
subl %ecx, %eax
ret

View File

@@ -1,28 +1,3 @@
.global memchr
memchr:
movb %sil, %al
movq %rdx, %rcx
movq $1, %rdx
cmpq $1, %rcx # clear ZF if count is zero
repne scasb
cmoveq %rdi, %rdx
leaq -1(%rdx), %rax
ret
.global memcmp
memcmp:
movq %rdx, %rcx
testq %rcx, %rcx # set ZF if count is zero
repe cmpsb
jne .memcmp_not_equal
xorq %rax, %rax
ret
.memcmp_not_equal:
movzbl -1(%rdi), %eax
movzbl -1(%rsi), %ecx
subq %rcx, %rax
ret
.global memcpy
memcpy:
movq %rdi, %rax
@@ -52,11 +27,154 @@ memset:
movq %r8, %rax
ret
#if defined(__SSE2__)
.global memchr
memchr:
testq %rdx, %rdx
jz .memchr_no_match
movd %esi, %xmm0
punpcklbw %xmm0, %xmm0
punpcklwd %xmm0, %xmm0
pshufd $0, %xmm0, %xmm0
movq %rdi, %rcx
andq $15, %rcx
jz .memchr_loop
movq %rdi, %rsi
subq %rcx, %rsi
movdqa (%rsi), %xmm1
pcmpeqb %xmm0, %xmm1
pmovmskb %xmm1, %eax
shrl %cl, %eax
jnz .memchr_match
leaq 16(%rsi), %rdi
addq %rcx, %rdx
subq $16, %rdx
jbe .memchr_no_match
.memchr_loop:
movdqa (%rdi), %xmm1
pcmpeqb %xmm0, %xmm1
pmovmskb %xmm1, %eax
testl %eax, %eax
jnz .memchr_match
addq $16, %rdi
subq $16, %rdx
ja .memchr_loop
.memchr_no_match:
xorq %rax, %rax
ret
.memchr_match:
bsfl %eax, %eax
cmpq %rdx, %rax
jae .memchr_no_match
addq %rdi, %rax
ret
.global memcmp
memcmp:
testq %rdx, %rdx
jz .memcmp_equal
movq %rdi, %rax
movq %rsi, %rcx
andq $15, %rax
andq $15, %rcx
cmpq %rax, %rcx
cmovaq %rcx, %rax
testq %rax, %rax
jz .memcmp_loop
movq $16, %rcx
subq %rax, %rcx
cmpq %rcx, %rdx
cmovbq %rdx, %rcx
subq %rcx, %rdx
.memcmp_align_loop:
movzbl (%rdi), %eax
movzbl (%rsi), %r8d
subl %r8d, %eax
jnz .memcmp_return
incq %rdi
incq %rsi
decq %rcx
jnz .memcmp_align_loop
.memcmp_loop:
movdqu (%rdi), %xmm0
movdqu (%rsi), %xmm1
pcmpeqb %xmm0, %xmm1
pmovmskb %xmm1, %eax
xorl $0xFFFF, %eax
jnz .memcmp_differ
addq $16, %rdi
addq $16, %rsi
subq $16, %rdx
ja .memcmp_loop
.memcmp_equal:
xorl %eax, %eax
.memcmp_return:
ret
.memcmp_differ:
bsfl %eax, %ecx
cmpq %rdx, %rcx
jae .memcmp_equal
movzbl (%rdi, %rcx), %eax
movzbl (%rsi, %rcx), %edx
subl %edx, %eax
ret
.global strlen
strlen:
xorb %al, %al
movq $-1, %rcx
repne scasb
movq $-2, %rax
subq %rcx, %rax
movq %rdi, %rsi
pxor %xmm0, %xmm0
movq %rsi, %rcx
andq $15, %rcx
jz .strlen_loop
movq %rsi, %rdx
subq %rcx, %rdx
movdqa (%rdx), %xmm1
pcmpeqb %xmm0, %xmm1
pmovmskb %xmm1, %eax
shrl %cl, %eax
jnz .strlen_null_found
leaq 16(%rdx), %rsi
.strlen_loop:
movdqa (%rsi), %xmm1
pcmpeqb %xmm0, %xmm1
pmovmskb %xmm1, %eax
testl %eax, %eax
jnz .strlen_null_found
addq $16, %rsi
jmp .strlen_loop
.strlen_null_found:
bsfl %eax, %eax
addq %rsi, %rax
subq %rdi, %rax
ret
#endif

View File

@@ -1,3 +1,4 @@
#include <ctype.h>
#include <fnmatch.h>
#include <stddef.h>
#include <stdint.h>
@@ -5,6 +6,8 @@
static int fnmatch_impl(const char* pattern, const char* string, int flags, bool leading)
{
const bool ignore_case = !!(flags & FNM_IGNORECASE);
while (*pattern)
{
if ((flags & FNM_PERIOD) && leading && *string == '.' && *pattern != '.')
@@ -34,9 +37,13 @@ static int fnmatch_impl(const char* pattern, const char* string, int flags, bool
uint8_t ch;
uint32_t bitmap[0x100 / 8] {};
while ((ch = *pattern++) != ']')
{
if (ignore_case)
ch = tolower(ch);
bitmap[ch / 32] |= 1 << (ch % 32);
}
ch = *string++;
ch = ignore_case ? tolower(*string++) : *string++;
if (!!(bitmap[ch / 32] & (1 << (ch % 32))) == negate)
return FNM_NOMATCH;
@@ -63,7 +70,10 @@ static int fnmatch_impl(const char* pattern, const char* string, int flags, bool
if (*pattern == '\0')
break;
if (*pattern != *string)
const char lhs = ignore_case ? tolower(*pattern) : *pattern;
const char rhs = ignore_case ? tolower(*string) : *string;
if (lhs != rhs)
return FNM_NOMATCH;
if ((flags & FNM_PATHNAME) && *string == '/')
leading = true;

View File

@@ -1,3 +1,11 @@
#ifndef assert
#ifdef NDEBUG
#define assert(ignore) ((void)0)
#else
#define assert(expr) ((expr) ? (void)0 : __assert_fail(#expr, __FILE__, __LINE__, __func__))
#endif
#endif
#ifndef _ASSERT_H
#define _ASSERT_H 1
@@ -5,12 +13,6 @@
#include <sys/cdefs.h>
#ifdef NDEBUG
#define assert(ignore) ((void)0)
#else
#define assert(expr) ((expr) ? (void)0 : __assert_fail(#expr, __FILE__, __LINE__, __func__))
#endif
#if !defined(__cplusplus) && __STDC_VERSION__ >= 201112L && __STDC_VERSION__ < 202311L
#define static_assert _Static_assert
#endif

View File

@@ -11,6 +11,8 @@ __BEGIN_DECLS
#define FNM_PATHNAME 0x01
#define FNM_PERIOD 0x02
#define FNM_NOESCAPE 0x04
#define FNM_CASEFOLD 0x08
#define FNM_IGNORECASE FNM_CASEFOLD
int fnmatch(const char* pattern, const char* string, int flags);

View File

@@ -53,6 +53,13 @@ struct ifreq
#define SIOCGIFFLAGS 9
#define SIOCGIFMTU 10
#define IFF_UP 0x01
#define IFF_BROADCAST 0x02
#define IFF_LOOPBACK 0x04
#define IFF_POINTOPOINT 0x08
#define IFF_RUNNING 0x10
#define IFF_MULTICAST 0x20
void if_freenameindex(struct if_nameindex* ptr);
char* if_indextoname(unsigned ifindex, char* ifname);
struct if_nameindex* if_nameindex(void);

View File

@@ -18,49 +18,26 @@ __BEGIN_DECLS
#define IPPROTO_TCP 6
#define IPPROTO_UDP 7
enum
{
IP_ADD_MEMBERSHIP,
#define IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP
IP_ADD_SOURCE_MEMBERSHIP,
#define IP_ADD_SOURCE_MEMBERSHIP IP_ADD_SOURCE_MEMBERSHIP
IP_DROP_MEMBERSHIP,
#define IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP
IP_DROP_SOURCE_MEMBERSHIP,
#define IP_DROP_SOURCE_MEMBERSHIP IP_DROP_SOURCE_MEMBERSHIP
IP_MULTICAST_IF,
#define IP_MULTICAST_IF IP_MULTICAST_IF
IP_MULTICAST_LOOP,
#define IP_MULTICAST_LOOP IP_MULTICAST_LOOP
IP_MULTICAST_TTL,
#define IP_MULTICAST_TTL IP_MULTICAST_TTL
IP_TTL,
#define IP_TTL IP_TTL
IP_TOS,
#define IP_TOS IP_TOS
};
#define IP_ADD_MEMBERSHIP 0
#define IP_ADD_SOURCE_MEMBERSHIP 1
#define IP_DROP_MEMBERSHIP 2
#define IP_DROP_SOURCE_MEMBERSHIP 3
#define IP_MULTICAST_IF 4
#define IP_MULTICAST_LOOP 5
#define IP_MULTICAST_TTL 6
#define IP_TTL 7
#define IP_TOS 8
enum
{
IPV6_ADD_MEMBERSHIP,
#define IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
IPV6_DROP_MEMBERSHIP,
#define IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
IPV6_JOIN_GROUP,
#define IPV6_JOIN_GROUP IPV6_JOIN_GROUP
IPV6_LEAVE_GROUP,
#define IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP
IPV6_MULTICAST_HOPS,
#define IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS
IPV6_MULTICAST_IF,
#define IPV6_MULTICAST_IF IPV6_MULTICAST_IF
IPV6_MULTICAST_LOOP,
#define IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP
IPV6_UNICAST_HOPS,
#define IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS
IPV6_V6ONLY,
#define IPV6_V6ONLY IPV6_V6ONLY
};
#define IPV6_ADD_MEMBERSHIP 0
#define IPV6_DROP_MEMBERSHIP 1
#define IPV6_JOIN_GROUP 2
#define IPV6_LEAVE_GROUP 3
#define IPV6_MULTICAST_HOPS 4
#define IPV6_MULTICAST_IF 5
#define IPV6_MULTICAST_LOOP 6
#define IPV6_UNICAST_HOPS 7
#define IPV6_V6ONLY 8
#define IPV6_TCLASS 9
#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0)
#define IN_CLASSA_NET 0xFF000000

View File

@@ -28,6 +28,8 @@ int sched_setparam(pid_t pid, const struct sched_param* param);
int sched_setscheduler(pid_t pid, int, const struct sched_param* param);
int sched_yield(void);
int sched_getcpu(void);
__END_DECLS
#endif

View File

@@ -42,6 +42,7 @@ char* strndup(const char* s, size_t n);
size_t strnlen(const char* s, size_t maxlen);
char* strpbrk(const char* s1, const char* s2);
char* strrchr(const char* s, int c);
char* strsep(char** __restrict stringp, const char* __restrict delim);
char* strsignal(int signum);
size_t strspn(const char* s1, const char* s2);
char* strstr(const char* s1, const char* s2);

View File

@@ -5,6 +5,8 @@
__BEGIN_DECLS
#include <stdint.h>
#define I_ATMARK 1
#define I_CANPUT 2
#define I_CKBAND 3
@@ -50,6 +52,13 @@ struct winsize
#define TIOCGWINSZ 50
#define TIOCSWINSZ 51
struct snd_volume_info
{
int32_t min_mdB;
int32_t max_mdB;
int32_t step_mdB;
int32_t mdB;
};
#define SND_GET_CHANNELS 60 /* stores number of channels to uint32_t argument */
#define SND_GET_SAMPLE_RATE 61 /* stores sample rate to uint32_t argument */
#define SND_RESET_BUFFER 62 /* stores the size of internal buffer to uint32_t argument and clears the buffer */
@@ -57,6 +66,8 @@ struct winsize
#define SND_GET_TOTAL_PINS 64 /* gets the number of pins on the current device as uint32_t */
#define SND_GET_PIN 65 /* gets the currently active pin as uint32_t */
#define SND_SET_PIN 66 /* sets the currently active pin to uint32_t */
#define SND_GET_VOLUME_INFO 67 /* gets the current volume as snd_volume_info */
#define SND_SET_VOLUME_MDB 68 /* sets the current volume to int32_t dB */
#define JOYSTICK_GET_LEDS 80 /* get controller led bitmap to uint8_t argument */
#define JOYSTICK_SET_LEDS 81 /* set controller leds to uint8_t bitmap */

View File

@@ -494,6 +494,10 @@ enum
#define _SC_XOPEN_UUCP _SC_XOPEN_UUCP
_SC_XOPEN_VERSION,
#define _SC_XOPEN_VERSION _SC_XOPEN_VERSION
_SC_PHYS_PAGES,
#define _SC_PHYS_PAGES _SC_PHYS_PAGES
_SC_AVPHYS_PAGES,
#define _SC_AVPHYS_PAGES _SC_AVPHYS_PAGES
};
#define F_OK 0x01

View File

@@ -256,7 +256,7 @@ FUNC_EXPR1(nearbyint, BAN::Math::rint(a))
FUNC_EXPR2(nextafter, nextafter_impl(a, b))
FUNC_EXPR2_TYPE(nexttoward, long double, nextafter_impl(a, b))
FUNC_EXPR2(pow, ({ if (isnan(a)) return a; if (isnan(b)) return b; BAN::Math::pow(a, b); }))
// remainder
BAN_FUNC2(remainder)
// remquo
BAN_FUNC1(rint)
FUNC_EXPR1(round, ({ if (!isfinite(a)) return a; BAN::Math::round(a); }))

View File

@@ -2,6 +2,10 @@
#include <sys/syscall.h>
#include <unistd.h>
#include <kernel/API/SharedPage.h>
extern volatile Kernel::API::SharedPage* g_shared_page;
int sched_get_priority_max(int policy)
{
(void)policy;
@@ -18,3 +22,17 @@ int sched_yield(void)
{
return syscall(SYS_YIELD);
}
int sched_getcpu(void)
{
if (g_shared_page == nullptr)
return -1;
uint8_t cpu;
#if defined(__x86_64__)
asm volatile("movb %%gs:0, %0" : "=r"(cpu));
#elif defined(__i686__)
asm volatile("movb %%fs:0, %0" : "=q"(cpu));
#endif
return cpu;
}

View File

@@ -49,8 +49,12 @@ int sem_timedwait(sem_t* __restrict sem, const struct timespec* __restrict absti
for (;;)
{
uint32_t expected = BAN::atomic_load(sem->value);
if (expected > 0 && BAN::atomic_compare_exchange(sem->value, expected, expected - 1))
if (expected > 0)
{
if (!BAN::atomic_compare_exchange(sem->value, expected, expected - 1))
continue;
return 0;
}
const int op = FUTEX_WAIT | (sem->shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME;
if (futex(op, &sem->value, expected, abstime) == -1 && (errno == EINTR || errno == ETIMEDOUT))

View File

@@ -169,7 +169,7 @@ static mode_t parse_mode_string(const char* mode_str)
return 0;
if (len == 3 && mode_str[1] == mode_str[2])
return 0;
if (strspn(mode_str + 1, "b+") != len - 1)
if (strspn(mode_str + 1, "tb+") != len - 1)
return 0;
bool plus = (mode_str[1] == '+' || mode_str[2] == '+');
switch (mode_str[0])

View File

@@ -274,6 +274,25 @@ char* strrchr(const char* str, int c)
return (*str == c) ? (char*)str : nullptr;
}
char* strsep(char** __restrict stringp, const char* __restrict delim)
{
if (*stringp == nullptr)
return nullptr;
char* original = *stringp;
char* match = strpbrk(*stringp, delim);
if (match == nullptr)
*stringp = nullptr;
else
{
*stringp = match + 1;
*match = '\0';
}
return original;
}
char* strstr(const char* haystack, const char* needle)
{
const size_t needle_len = strlen(needle);

View File

@@ -19,6 +19,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/banan-os.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
@@ -1180,6 +1181,25 @@ long sysconf(int name)
case _SC_GETGR_R_SIZE_MAX: return 1024;
case _SC_GETPW_R_SIZE_MAX: return 1024;
case _SC_THREAD_STACK_MIN: return PTHREAD_STACK_MIN;
case _SC_PHYS_PAGES:
case _SC_AVPHYS_PAGES:
{
int fd = open("/proc/meminfo", O_RDONLY);
if (fd == -1)
return -1;
full_meminfo_t meminfo;
const size_t nread = read(fd, &meminfo, sizeof(meminfo));
close(fd);
if (nread != sizeof(meminfo))
return -1;
if (name == _SC_PHYS_PAGES)
return meminfo.free_pages + meminfo.used_pages;
if (name == _SC_AVPHYS_PAGES)
return meminfo.free_pages;
}
}
errno = EINVAL;

View File

@@ -98,12 +98,53 @@ bool AudioServer::on_client_packet(int fd, LibAudio::Packet packet)
return false;
}
reset_kernel_buffer();
if (uint32_t pin = packet.parameter; ioctl(device().fd, SND_SET_PIN, &pin) != 0)
if (ioctl(device().fd, SND_SET_PIN, &packet.parameter) != 0)
dwarnln("Failed to set pin {}: {}", packet.parameter, strerror(errno));
else
{
device().current_pin = packet.parameter;
// NOTE: different pins have different volume controls
if (ioctl(device().fd, SND_GET_VOLUME_INFO, &device().volume) != 0)
dwarnln("Failed to query new volume: {}", strerror(errno));
}
update();
break;
case LibAudio::Packet::GetVolume:
{
// NOTE: maybe we should map [0->100%] -> [min, 0] instead?
const auto& volume = device().volume;
if (volume.min_mdB == volume.max_mdB)
response = 1000;
else
{
const double min_dB = volume.min_mdB / 1000.0;
const double max_dB = volume.max_mdB / 1000.0;
const double dB = volume.mdB / 1000.0;
const double percent = (BAN::Math::pow(10.0, (dB - min_dB) / (max_dB - min_dB)) - 1.0) / 9.0;
response = BAN::Math::round(percent * 1000.0);
}
break;
}
case LibAudio::Packet::SetVolume:
{
// NOTE: maybe we should map [0->100%] -> [min, 0] instead?
const auto& volume = device().volume;
const double min_dB = volume.min_mdB / 1000.0;
const double max_dB = volume.max_mdB / 1000.0;
const double percent = packet.parameter / 1000.0;
const double dB = min_dB + (max_dB - min_dB) * BAN::Math::log10(1.0 + 9.0 * percent);
const int32_t mdB = BAN::Math::round(dB * 1000.0);
if (ioctl(device().fd, SND_SET_VOLUME_MDB, &mdB) != 0)
dwarnln("Failed to set volume: {}", strerror(errno));
else if (ioctl(device().fd, SND_GET_VOLUME_INFO, &device().volume) != 0)
dwarnln("Failed to query new volume: {}", strerror(errno));
break;
}
default:
dwarnln("unknown packet type {}", static_cast<uint8_t>(packet.type));
return false;
@@ -278,7 +319,7 @@ void AudioServer::send_samples()
for (size_t i = 0; i < samples_to_send; i++)
{
sample_buffer[i] = BAN::Math::clamp<sample_t>(
0.2 * m_samples[m_samples_sent + i] * BAN::numeric_limits<kernel_sample_t>::max(),
m_samples[m_samples_sent + i] * BAN::numeric_limits<kernel_sample_t>::max(),
BAN::numeric_limits<kernel_sample_t>::min(),
BAN::numeric_limits<kernel_sample_t>::max()
);

View File

@@ -8,6 +8,8 @@
#include <LibAudio/Audio.h>
#include <LibAudio/Protocol.h>
#include <sys/ioctl.h>
struct AudioDevice
{
int fd;
@@ -15,6 +17,7 @@ struct AudioDevice
uint32_t sample_rate;
uint32_t total_pins;
uint32_t current_pin;
snd_volume_info volume;
};
class AudioServer

View File

@@ -68,6 +68,8 @@ static BAN::Optional<AudioDevice> initialize_audio_device(int fd)
return {};
if (ioctl(fd, SND_GET_PIN, &result.current_pin) != 0)
return {};
if (ioctl(fd, SND_GET_VOLUME_INFO, &result.volume) != 0)
return {};
return result;
}

View File

@@ -7,6 +7,7 @@ banan_link_library(TaskBar ban)
banan_link_library(TaskBar libc)
banan_link_library(TaskBar libfont)
banan_link_library(TaskBar libgui)
banan_include_headers(TaskBar libaudio)
banan_include_headers(TaskBar libinput)
install(TARGETS TaskBar OPTIONAL)

View File

@@ -1,9 +1,12 @@
#include <LibAudio/Protocol.h>
#include <LibFont/Font.h>
#include <LibGUI/Window.h>
#include <dirent.h>
#include <fcntl.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/un.h>
static BAN::ErrorOr<long long> read_integer_from_file(const char* file)
{
@@ -60,12 +63,57 @@ static BAN::String get_battery_percentage()
return result;
}
static int open_audio_server_fd()
{
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
return -1;
sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, LibAudio::s_audio_server_socket.data());
if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
return -1;
return fd;
}
static BAN::String get_audio_volume()
{
static int fd = -1;
if (fd == -1 && (fd = open_audio_server_fd()) == -1)
return {};
const LibAudio::Packet request {
.type = LibAudio::Packet::GetVolume,
.parameter = {},
};
if (send(fd, &request, sizeof(request), 0) != sizeof(request))
{
close(fd);
fd = -1;
return {};
}
uint32_t response;
if (recv(fd, &response, sizeof(response), 0) != sizeof(response))
{
close(fd);
fd = -1;
return {};
}
return MUST(BAN::String::formatted("vol {}% | ", response / 10));
}
static BAN::ErrorOr<BAN::String> get_task_bar_string()
{
BAN::String result;
TRY(result.append(get_battery_percentage()));
TRY(result.append(get_audio_volume()));
const time_t current_time = time(nullptr);
TRY(result.append(ctime(&current_time)));
result.pop_back();
@@ -79,6 +127,8 @@ int main()
constexpr uint32_t bg_color = 0xFF202020;
constexpr uint32_t fg_color = 0xFFFFFFFF;
signal(SIGUSR1, [](int) {});
auto font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv));
auto attributes = LibGUI::Window::default_attributes;
@@ -99,7 +149,8 @@ int main()
bool is_running = true;
const auto update_time_string =
uint32_t old_text_w = 0;
const auto update_string =
[&]()
{
auto text_or_error = get_task_bar_string();
@@ -112,15 +163,20 @@ int main()
const uint32_t text_x = window->width() - text_w - padding;
const uint32_t text_y = padding;
const uint32_t inval_w = BAN::Math::max(text_w, old_text_w);
const uint32_t inval_x = window->width() - inval_w - padding;
auto& texture = window->texture();
texture.fill_rect(text_x, text_y, text_w, text_h, bg_color);
texture.fill_rect(inval_x, text_y, inval_w, text_h, bg_color);
texture.draw_text(text, font, text_x, text_y, fg_color);
window->invalidate(text_x, text_y, text_w, text_h);
window->invalidate(inval_x, text_y, inval_w, text_h);
old_text_w = text_w;
};
while (is_running)
{
update_time_string();
update_string();
constexpr uint64_t ns_per_s = 1'000'000'000;

View File

@@ -418,11 +418,23 @@ void WindowServer::on_window_set_cursor(int fd, const LibGUI::WindowPacket::Wind
invalidate(cursor_area().get_bounding_box(old_cursor));
}
static void update_volume(const char* new_volume)
{
char command[128];
sprintf(command, "audioctl --volume %s && kill -USR1 TaskBar", new_volume);
system(command);
}
void WindowServer::on_key_event(LibInput::KeyEvent event)
{
if (event.key == LibInput::Key::Super)
m_is_mod_key_held = event.pressed();
if (event.pressed() && event.key == LibInput::Key::VolumeDown)
update_volume("-5");
if (event.pressed() && event.key == LibInput::Key::VolumeUp)
update_volume("+5");
// Stop WindowServer with mod+shift+E
if (m_is_mod_key_held && event.pressed() && event.shift() && event.key == LibInput::Key::E)
{

View File

@@ -74,17 +74,20 @@ static uint32_t send_request(int fd, LibAudio::Packet packet, bool wait_response
static void list_devices(int fd)
{
const uint32_t current_device = send_request(fd, { .type = LibAudio::Packet::GetDevice, .parameter = 0 }, true);
const uint32_t current_pin = send_request(fd, { .type = LibAudio::Packet::GetPin, .parameter = 0 }, true);
const uint32_t current_device = send_request(fd, { .type = LibAudio::Packet::GetDevice, .parameter = {} }, true);
const uint32_t current_pin = send_request(fd, { .type = LibAudio::Packet::GetPin, .parameter = {} }, true);
const uint32_t total_devices = send_request(fd, { .type = LibAudio::Packet::QueryDevices, .parameter = 0 }, true);
const uint32_t total_devices = send_request(fd, { .type = LibAudio::Packet::QueryDevices, .parameter = {} }, true);
for (uint32_t dev = 0; dev < total_devices; dev++)
{
const uint32_t total_pins = send_request(fd, { .type = LibAudio::Packet::QueryPins, .parameter = dev }, true);
printf("Device %" PRIu32 "", dev);
if (dev == current_device)
printf(" (current)");
{
const uint32_t volume = send_request(fd, { .type = LibAudio::Packet::GetVolume, .parameter = {} }, true);
printf(" (current) %" PRIu32 "%%", volume / 10);
}
printf("\n");
for (uint32_t pin = 0; pin < total_pins; pin++)
@@ -103,16 +106,20 @@ int main(int argc, char** argv)
BAN::Optional<uint32_t> device;
BAN::Optional<uint32_t> pin;
BAN::Optional<uint32_t> volume;
BAN::Optional<bool> volume_rel; // no value: absolute, false positive, true negative
for (;;)
{
static option long_options[] {
{ "list", no_argument, nullptr, 'l' },
{ "device", required_argument, nullptr, 'd' },
{ "pin", required_argument, nullptr, 'p' },
{ "volume", required_argument, nullptr, 'v' },
{ "help", no_argument, nullptr, 'h' },
};
int ch = getopt_long(argc, argv, "ld:p:h", long_options, nullptr);
int ch = getopt_long(argc, argv, "ld:p:v:h", long_options, nullptr);
if (ch == -1)
break;
@@ -125,6 +132,7 @@ int main(int argc, char** argv)
fprintf(stderr, " -l, --list list devices and their pins\n");
fprintf(stderr, " -d, --device N set device index N as the current one\n");
fprintf(stderr, " -p, --pin N set pin N as the current one\n");
fprintf(stderr, " -v, --volume N set volume to N%%. if + or - is given, volume is relative to the current volume\n");
fprintf(stderr, " -h, --help show this message and exit\n");
return 0;
case 'l':
@@ -136,6 +144,11 @@ int main(int argc, char** argv)
case 'p':
pin = parse_u32_or_exit(optarg);
break;
case 'v':
if (optarg[0] == '-' || optarg[0] == '+')
volume_rel = (optarg[0] == '-');
volume = parse_u32_or_exit(optarg + volume_rel.has_value());
break;
case '?':
fprintf(stderr, "invalid option %c\n", optopt);
fprintf(stderr, "see '%s --help' for usage\n", argv[0]);
@@ -143,7 +156,7 @@ int main(int argc, char** argv)
}
}
if (!device.has_value() && !pin.has_value())
if (!device.has_value() && !pin.has_value() && !volume.has_value())
list = true;
const int fd = get_server_fd();
@@ -156,6 +169,30 @@ int main(int argc, char** argv)
if (pin.has_value())
send_request(fd, { .type = LibAudio::Packet::SetPin, .parameter = pin.value() }, false);
if (volume.has_value())
{
const uint32_t volume10 = volume.value() * 10;
uint32_t param;
if (!volume_rel.has_value())
param = volume10;
else
{
const uint32_t current = send_request(fd, { .type = LibAudio::Packet::GetVolume, .parameter = {} }, true);
if (!volume_rel.value())
param = current + volume10;
else
{
if (current > volume10)
param = current - volume10;
else
param = 0;
}
}
send_request(fd, { .type = LibAudio::Packet::SetVolume, .parameter = param }, false);
}
if (list)
list_devices(fd);

View File

@@ -1,5 +1,7 @@
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@@ -65,12 +67,18 @@ static int signal_name_to_number(const char* name)
exit_with_error("unknown signal '%s'\n", name);
}
static int parse_int(const char* string)
static bool parse_int_safe(const char* string, int& out)
{
errno = 0;
char* endptr;
const int result = strtol(string, &endptr, 0);
if (*endptr != '\0' || errno)
out = strtol(string, &endptr, 0);
return *endptr == '\0' && errno == 0;
}
static int parse_int(const char* string)
{
int result;
if (!parse_int_safe(string, result))
exit_with_error("invalid integer '%s'\n", string);
return result;
}
@@ -166,9 +174,61 @@ int main(int argc, char** argv)
if (i >= argc)
exit_with_error("missing pids\n");
DIR* proc_dirp = opendir("/proc");
if (proc_dirp == NULL)
perror("opendir");
for (; i < argc; i++)
if (kill(parse_int(argv[i]), sig) == -1)
{
pid_t pid;
if (parse_int_safe(argv[i], pid))
{
if (kill(pid, sig) == -1)
perror("kill");
continue;
}
const size_t arg_len = strlen(argv[i]);
if (proc_dirp == NULL || arg_len >= NAME_MAX)
{
fprintf(stderr, "cannot find process \"%s\"\n", argv[i]);
continue;
}
bool found = false;
dirent* dirent;
rewinddir(proc_dirp);
while ((dirent = readdir(proc_dirp)))
{
if (dirent->d_type != DT_DIR || !isdigit(dirent->d_name[0]))
continue;
char path_buffer[PATH_MAX + 8];
sprintf(path_buffer, "%s/cmdline", dirent->d_name);
int fd = openat(dirfd(proc_dirp), path_buffer, O_RDONLY);
if (fd == -1)
continue;
char buffer[NAME_MAX + 1];
const ssize_t nread = read(fd, buffer, arg_len + 1);
close(fd);
if (nread != static_cast<ssize_t>(arg_len + 1) || strcmp(argv[i], buffer) != 0)
continue;
if (kill(parse_int(dirent->d_name), sig) == -1)
perror("kill");
found = true;
}
if (!found)
fprintf(stderr, "cannot find process \"%s\"\n", argv[i]);
}
if (proc_dirp)
closedir(proc_dirp);
return 0;
}