Compare commits
39
Commits
c915c064e8
...
315d8895a7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
315d8895a7 | ||
|
|
4e9cfdde97 | ||
|
|
645b6d772d | ||
|
|
ae24fb1dd0 | ||
|
|
fe64639842 | ||
|
|
db9beac740 | ||
|
|
471b6a6c40 | ||
|
|
fe2b130915 | ||
|
|
67fdd24a19 | ||
|
|
0d6b32dc3c | ||
|
|
ffceb300db | ||
|
|
b818e2764c | ||
|
|
4b7d90f939 | ||
|
|
6a7c1c1281 | ||
|
|
fdbfda189f | ||
|
|
e496d889ba | ||
|
|
9967878886 | ||
|
|
51badd75f0 | ||
|
|
f6e841e623 | ||
|
|
28bd9cf353 | ||
|
|
892829adeb | ||
|
|
82fd57af9e | ||
|
|
2f25bfb2db | ||
|
|
7f12e5aaf3 | ||
|
|
78e40ca353 | ||
|
|
1231b16cc3 | ||
|
|
6cd3638a85 | ||
|
|
4aead25970 | ||
|
|
36b34b0df0 | ||
|
|
bf0bd19289 | ||
|
|
8cd9e6dfa8 | ||
|
|
f0a114f4e5 | ||
|
|
ac99bf128b | ||
|
|
2c66de888f | ||
|
|
8f4db57ed8 | ||
|
|
b6f922895f | ||
|
|
7aa8eb1778 | ||
|
|
1128e440d2 | ||
|
|
ac052fe1c1 |
+32
-5
@@ -82,6 +82,37 @@ namespace BAN::Math
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
template<unsigned_integral T>
|
||||
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
||||
inline constexpr int clz(T x)
|
||||
{
|
||||
if constexpr (is_same_v<T, unsigned int>)
|
||||
return __builtin_clz(x);
|
||||
if constexpr (is_same_v<T, unsigned long>)
|
||||
return __builtin_clzl(x);
|
||||
return __builtin_clzll(x);
|
||||
}
|
||||
|
||||
template<unsigned_integral T> requires(sizeof(T) <= sizeof(unsigned long long))
|
||||
inline constexpr int ctz(T x)
|
||||
{
|
||||
if constexpr (sizeof(T) <= sizeof(unsigned int))
|
||||
return __builtin_ctz(x);
|
||||
if constexpr (sizeof(T) <= sizeof(unsigned long))
|
||||
return __builtin_ctzl(x);
|
||||
return __builtin_ctzll(x);
|
||||
}
|
||||
|
||||
template<unsigned_integral T> requires(sizeof(T) <= sizeof(unsigned long long))
|
||||
inline constexpr int popcount(T x)
|
||||
{
|
||||
if constexpr (sizeof(T) <= sizeof(unsigned int))
|
||||
return __builtin_popcount(x);
|
||||
if constexpr (sizeof(T) <= sizeof(unsigned long))
|
||||
return __builtin_popcountl(x);
|
||||
return __builtin_popcountll(x);
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
__attribute__((always_inline))
|
||||
inline constexpr bool will_multiplication_overflow(T a, T b)
|
||||
@@ -102,11 +133,7 @@ namespace BAN::Math
|
||||
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
||||
inline constexpr T ilog2(T x)
|
||||
{
|
||||
if constexpr(is_same_v<T, unsigned int>)
|
||||
return sizeof(T) * 8 - __builtin_clz(x) - 1;
|
||||
if constexpr(is_same_v<T, unsigned long>)
|
||||
return sizeof(T) * 8 - __builtin_clzl(x) - 1;
|
||||
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
||||
return sizeof(T) * 8 - clz(x) - 1;
|
||||
}
|
||||
|
||||
// This is ugly but my clangd does not like including
|
||||
|
||||
Binary file not shown.
@@ -51,6 +51,8 @@ set(KERNEL_SOURCES
|
||||
kernel/Interruptable.cpp
|
||||
kernel/InterruptController.cpp
|
||||
kernel/kernel.cpp
|
||||
kernel/Lock/Mutex.cpp
|
||||
kernel/Lock/RWLock.cpp
|
||||
kernel/Lock/SpinLock.cpp
|
||||
kernel/Memory/ByteRingBuffer.cpp
|
||||
kernel/Memory/DMARegion.cpp
|
||||
@@ -83,6 +85,7 @@ set(KERNEL_SOURCES
|
||||
kernel/Processor.cpp
|
||||
kernel/Random.cpp
|
||||
kernel/Scheduler.cpp
|
||||
kernel/SchedulerThreadNode.cpp
|
||||
kernel/SSP.cpp
|
||||
kernel/Storage/ATA/AHCI/Controller.cpp
|
||||
kernel/Storage/ATA/AHCI/Device.cpp
|
||||
|
||||
@@ -63,7 +63,7 @@ sys_fork_trampoline:
|
||||
|
||||
call read_ip
|
||||
testl %eax, %eax
|
||||
jz .done
|
||||
jz .Lsys_fork_trampoline_done
|
||||
|
||||
movl %esp, %ebx
|
||||
|
||||
@@ -73,7 +73,7 @@ sys_fork_trampoline:
|
||||
call sys_fork
|
||||
addl $16, %esp
|
||||
|
||||
.done:
|
||||
.Lsys_fork_trampoline_done:
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
|
||||
@@ -28,27 +28,26 @@ safe_user_strncpy:
|
||||
testl %ecx, %ecx
|
||||
jz safe_user_strncpy_fault
|
||||
|
||||
.safe_user_strncpy_loop:
|
||||
.Lsafe_user_strncpy_loop:
|
||||
movb (%esi), %al
|
||||
movb %al, (%edi)
|
||||
testb %al, %al
|
||||
jz .safe_user_strncpy_done
|
||||
jz .Lsafe_user_strncpy_done
|
||||
|
||||
incl %edi
|
||||
incl %esi
|
||||
decl %ecx
|
||||
jnz .safe_user_strncpy_loop
|
||||
jnz .Lsafe_user_strncpy_loop
|
||||
|
||||
safe_user_strncpy_fault:
|
||||
xorl %eax, %eax
|
||||
jmp .safe_user_strncpy_return
|
||||
jmp .Lsafe_user_strncpy_return
|
||||
|
||||
.safe_user_strncpy_done:
|
||||
.Lsafe_user_strncpy_done:
|
||||
movl $1, %eax
|
||||
|
||||
.safe_user_strncpy_return:
|
||||
.Lsafe_user_strncpy_return:
|
||||
movl 4(%esp), %edi
|
||||
movl 8(%esp), %esi
|
||||
ret
|
||||
|
||||
safe_user_strncpy_end:
|
||||
|
||||
+15
-17
@@ -168,14 +168,12 @@ has_sse:
|
||||
|
||||
check_requirements:
|
||||
call has_cpuid
|
||||
jz .exit
|
||||
jz system_halt
|
||||
call has_pae
|
||||
jz .exit
|
||||
jz system_halt
|
||||
call has_sse
|
||||
jz .exit
|
||||
jz system_halt
|
||||
ret
|
||||
.exit:
|
||||
jmp system_halt
|
||||
|
||||
enable_sse:
|
||||
movl %cr0, %eax
|
||||
@@ -225,8 +223,8 @@ _start:
|
||||
|
||||
# load boot GDT
|
||||
lgdt V2P(boot_gdtr)
|
||||
ljmpl $0x08, $V2P(gdt_flush)
|
||||
gdt_flush:
|
||||
ljmpl $0x08, $V2P(.Lgdt_flush)
|
||||
.Lgdt_flush:
|
||||
# set correct segment registers
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
@@ -243,10 +241,10 @@ gdt_flush:
|
||||
movl $g_boot_stack_top, %esp
|
||||
|
||||
# jump to higher half
|
||||
leal higher_half, %ecx
|
||||
leal .Lhigher_half, %ecx
|
||||
jmp *%ecx
|
||||
|
||||
higher_half:
|
||||
.Lhigher_half:
|
||||
# call global constuctors
|
||||
call _init
|
||||
|
||||
@@ -298,18 +296,18 @@ ap_ready:
|
||||
.skip 4
|
||||
|
||||
1: cli; cld
|
||||
ljmpl $0x00, $AP_REL(ap_cs_clear)
|
||||
ljmpl $0x00, $AP_REL(.Lap_cs_clear)
|
||||
|
||||
ap_cs_clear:
|
||||
.Lap_cs_clear:
|
||||
# load ap gdt and enter protected mode
|
||||
lgdt AP_REL(ap_gdtr)
|
||||
movl %cr0, %eax
|
||||
orb $1, %al
|
||||
movl %eax, %cr0
|
||||
ljmpl $0x08, $AP_REL(ap_protected_mode)
|
||||
ljmpl $0x08, $AP_REL(.Lap_protected_mode)
|
||||
|
||||
.code32
|
||||
ap_protected_mode:
|
||||
.Lap_protected_mode:
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %ss
|
||||
@@ -323,13 +321,13 @@ ap_protected_mode:
|
||||
|
||||
# load boot gdt and enter long mode
|
||||
lgdt V2P(boot_gdtr)
|
||||
ljmpl $0x08, $AP_REL(ap_flush_gdt)
|
||||
ljmpl $0x08, $AP_REL(.Lap_flush_gdt)
|
||||
|
||||
ap_flush_gdt:
|
||||
movl $ap_higher_half, %ecx
|
||||
.Lap_flush_gdt:
|
||||
movl $.Lap_higher_half, %ecx
|
||||
jmp *%ecx
|
||||
|
||||
ap_higher_half:
|
||||
.Lap_higher_half:
|
||||
movl AP_REL(ap_prepare_paging), %eax
|
||||
call *%eax
|
||||
|
||||
|
||||
@@ -33,13 +33,13 @@ sys_fork_trampoline:
|
||||
|
||||
call read_ip
|
||||
testq %rax, %rax
|
||||
jz .done
|
||||
jz .Lsys_fork_trampoline_done
|
||||
|
||||
movq %rax, %rsi
|
||||
movq %rsp, %rdi
|
||||
call sys_fork
|
||||
|
||||
.done:
|
||||
.Lsys_fork_trampoline_done:
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
|
||||
+14
-14
@@ -20,28 +20,28 @@ safe_user_strncpy:
|
||||
testq %rcx, %rcx
|
||||
jz safe_user_strncpy_fault
|
||||
|
||||
.safe_user_strncpy_align_loop:
|
||||
.Lsafe_user_strncpy_align_loop:
|
||||
testb $0x7, %sil
|
||||
jz .safe_user_strncpy_align_done
|
||||
jz .Lsafe_user_strncpy_align_done
|
||||
|
||||
movb (%rsi), %al
|
||||
movb %al, (%rdi)
|
||||
testb %al, %al
|
||||
jz .safe_user_strncpy_done
|
||||
jz .Lsafe_user_strncpy_done
|
||||
|
||||
incq %rdi
|
||||
incq %rsi
|
||||
decq %rcx
|
||||
jnz .safe_user_strncpy_align_loop
|
||||
jnz .Lsafe_user_strncpy_align_loop
|
||||
jmp safe_user_strncpy_fault
|
||||
|
||||
.safe_user_strncpy_align_done:
|
||||
.Lsafe_user_strncpy_align_done:
|
||||
movq $0x0101010101010101, %r8
|
||||
movq $0x8080808080808080, %r9
|
||||
|
||||
.safe_user_strncpy_qword_loop:
|
||||
.Lsafe_user_strncpy_qword_loop:
|
||||
cmpq $8, %rcx
|
||||
jb .safe_user_strncpy_qword_done
|
||||
jb .Lsafe_user_strncpy_qword_done
|
||||
|
||||
movq (%rsi), %rax
|
||||
movq %rax, %r10
|
||||
@@ -52,36 +52,36 @@ safe_user_strncpy:
|
||||
notq %r11
|
||||
andq %r11, %r10
|
||||
andq %r9, %r10
|
||||
jnz .safe_user_strncpy_byte_loop
|
||||
jnz .Lsafe_user_strncpy_byte_loop
|
||||
|
||||
movq %rax, (%rdi)
|
||||
|
||||
addq $8, %rdi
|
||||
addq $8, %rsi
|
||||
subq $8, %rcx
|
||||
jnz .safe_user_strncpy_qword_loop
|
||||
jnz .Lsafe_user_strncpy_qword_loop
|
||||
jmp safe_user_strncpy_fault
|
||||
|
||||
.safe_user_strncpy_qword_done:
|
||||
.Lsafe_user_strncpy_qword_done:
|
||||
testq %rcx, %rcx
|
||||
jz safe_user_strncpy_fault
|
||||
|
||||
.safe_user_strncpy_byte_loop:
|
||||
.Lsafe_user_strncpy_byte_loop:
|
||||
movb (%rsi), %al
|
||||
movb %al, (%rdi)
|
||||
testb %al, %al
|
||||
jz .safe_user_strncpy_done
|
||||
jz .Lsafe_user_strncpy_done
|
||||
|
||||
incq %rdi
|
||||
incq %rsi
|
||||
decq %rcx
|
||||
jnz .safe_user_strncpy_byte_loop
|
||||
jnz .Lsafe_user_strncpy_byte_loop
|
||||
|
||||
safe_user_strncpy_fault:
|
||||
xorq %rax, %rax
|
||||
ret
|
||||
|
||||
.safe_user_strncpy_done:
|
||||
.Lsafe_user_strncpy_done:
|
||||
movb $1, %al
|
||||
ret
|
||||
safe_user_strncpy_end:
|
||||
|
||||
+14
-16
@@ -161,12 +161,10 @@ is_64_bit:
|
||||
|
||||
check_requirements:
|
||||
call has_cpuid
|
||||
jz .exit
|
||||
jz system_halt
|
||||
call is_64_bit
|
||||
jz .exit
|
||||
jz system_halt
|
||||
ret
|
||||
.exit:
|
||||
jmp system_halt
|
||||
|
||||
enable_sse:
|
||||
movl %cr0, %eax
|
||||
@@ -226,10 +224,10 @@ _start:
|
||||
|
||||
# flush gdt and jump to 64 bit
|
||||
lgdt V2P(boot_gdtr)
|
||||
ljmpl $0x08, $V2P(long_mode)
|
||||
ljmpl $0x08, $V2P(.Llong_mode)
|
||||
|
||||
.code64
|
||||
long_mode:
|
||||
.Llong_mode:
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %ss
|
||||
@@ -240,10 +238,10 @@ long_mode:
|
||||
addq $KERNEL_OFFSET, %rsp
|
||||
|
||||
# jump to higher half
|
||||
movabsq $higher_half, %rcx
|
||||
movabsq $.Lhigher_half, %rcx
|
||||
jmp *%rcx
|
||||
|
||||
higher_half:
|
||||
.Lhigher_half:
|
||||
# call global constuctors
|
||||
call _init
|
||||
|
||||
@@ -293,18 +291,18 @@ ap_ready:
|
||||
.skip 8
|
||||
|
||||
1: cli; cld
|
||||
ljmpl $0x00, $AP_REL(ap_cs_clear)
|
||||
ljmpl $0x00, $AP_REL(.Lap_cs_clear)
|
||||
|
||||
ap_cs_clear:
|
||||
.Lap_cs_clear:
|
||||
# load ap gdt and enter protected mode
|
||||
lgdt AP_REL(ap_gdtr)
|
||||
movl %cr0, %eax
|
||||
orb $1, %al
|
||||
movl %eax, %cr0
|
||||
ljmpl $0x08, $AP_REL(ap_protected_mode)
|
||||
ljmpl $0x08, $AP_REL(.Lap_protected_mode)
|
||||
|
||||
.code32
|
||||
ap_protected_mode:
|
||||
.Lap_protected_mode:
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %ss
|
||||
@@ -318,14 +316,14 @@ ap_protected_mode:
|
||||
|
||||
# load boot gdt and enter long mode
|
||||
lgdt V2P(boot_gdtr)
|
||||
ljmpl $0x08, $AP_REL(ap_long_mode)
|
||||
ljmpl $0x08, $AP_REL(.Lap_long_mode)
|
||||
|
||||
.code64
|
||||
ap_long_mode:
|
||||
movq $ap_higher_half, %rax
|
||||
.Lap_long_mode:
|
||||
movq $.Lap_higher_half, %rax
|
||||
jmp *%rax
|
||||
|
||||
ap_higher_half:
|
||||
.Lap_higher_half:
|
||||
movq AP_REL(ap_prepare_paging), %rax
|
||||
call *%rax
|
||||
|
||||
|
||||
+26
-12
@@ -38,25 +38,39 @@ extern "C" void __cxa_finalize(void* f)
|
||||
}
|
||||
};
|
||||
|
||||
namespace __cxxabiv1
|
||||
extern "C" int __cxa_guard_acquire(uint64_t* g)
|
||||
{
|
||||
using __guard = uint64_t;
|
||||
uint8_t* guard = reinterpret_cast<uint8_t*>(g);
|
||||
|
||||
extern "C" int __cxa_guard_acquire (__guard* g)
|
||||
for (;;)
|
||||
{
|
||||
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
|
||||
uint8_t zero = 0;
|
||||
return __atomic_compare_exchange_n(byte, &zero, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
|
||||
if (BAN::atomic_load(guard[0], BAN::memory_order_acquire))
|
||||
return 0;
|
||||
|
||||
uint8_t expected = 0;
|
||||
if (BAN::atomic_compare_exchange(guard[1], expected, 1, BAN::memory_order_acquire))
|
||||
{
|
||||
if (BAN::atomic_load(guard[0], BAN::memory_order_acquire))
|
||||
{
|
||||
BAN::atomic_store(guard[1], 0, BAN::memory_order_release);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_release (__guard* g)
|
||||
{
|
||||
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
|
||||
__atomic_store_n(byte, 0, __ATOMIC_RELEASE);
|
||||
while (BAN::atomic_load(guard[1], BAN::memory_order_acquire))
|
||||
Kernel::Processor::pause();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_abort (__guard*)
|
||||
extern "C" void __cxa_guard_release(uint64_t* g)
|
||||
{
|
||||
uint8_t* guard = reinterpret_cast<uint8_t*>(g);
|
||||
BAN::atomic_store(guard[0], 1, BAN::memory_order_release);
|
||||
BAN::atomic_store(guard[1], 0, BAN::memory_order_release);
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_abort(uint64_t*)
|
||||
{
|
||||
Kernel::panic("__cxa_guard_abort");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/EmbeddedController.h>
|
||||
#include <kernel/ACPI/Headers.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/InterruptNumbers.h>
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ namespace Kernel
|
||||
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
|
||||
BAN::Vector<const HDAudio::AFGWidget*> m_output_pins;
|
||||
size_t m_output_path_index { SIZE_MAX };
|
||||
size_t m_amplifier_idx { SIZE_MAX };
|
||||
|
||||
uint8_t m_stream_id { 0xFF };
|
||||
uint8_t m_stream_index { 0xFF };
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace Kernel::HDAudio
|
||||
@@ -64,6 +65,7 @@ namespace Kernel::HDAudio
|
||||
};
|
||||
|
||||
BAN::Optional<Amplifier> output_amplifier;
|
||||
BAN::Optional<Amplifier> input_amplifier;
|
||||
|
||||
BAN::Vector<uint16_t> connections;
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <BAN/HashMap.h>
|
||||
#include <kernel/FS/Inode.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/Device/Device.h>
|
||||
#include <kernel/FS/TmpFS/FileSystem.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
@@ -9,6 +8,8 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Device;
|
||||
|
||||
class DevFileSystem final : public TmpFileSystem
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <kernel/FS/Inode.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
@@ -22,16 +23,16 @@ namespace Kernel
|
||||
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
|
||||
bool can_read_impl() const override { return m_value > 0; }
|
||||
bool can_write_impl() const override { return m_value < UINT64_MAX - 1; }
|
||||
bool can_read_impl() const override;
|
||||
bool can_write_impl() const override;
|
||||
bool has_error_impl() const override { return false; }
|
||||
bool has_hungup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
const bool m_is_semaphore;
|
||||
BAN::Atomic<uint64_t> m_value;
|
||||
uint64_t m_value;
|
||||
|
||||
Mutex m_mutex;
|
||||
mutable Mutex m_mutex;
|
||||
ThreadBlocker m_thread_blocker;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
#include <BAN/HashMap.h>
|
||||
#include <kernel/Device/Device.h>
|
||||
#include <kernel/FS/FileSystem.h>
|
||||
#include <kernel/FS/Ext2/Inode.h>
|
||||
#include <kernel/FS/FileSystem.h>
|
||||
#include <kernel/Memory/VirtualRange.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <kernel/FS/FAT/Definitions.h>
|
||||
#include <kernel/FS/FAT/Inode.h>
|
||||
#include <kernel/FS/FileSystem.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Device/Device.h>
|
||||
#include <kernel/FS/Inode.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class BlockDevice;
|
||||
|
||||
class FileSystem : public BAN::RefCounted<FileSystem>
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
#include <kernel/FS/TmpFS/FileSystem.h>
|
||||
#include <kernel/FS/TmpFS/Inode.h>
|
||||
#include <kernel/Process.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Process;
|
||||
|
||||
class ProcFileSystem final : public TmpFileSystem
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
#include <kernel/FS/TmpFS/FileSystem.h>
|
||||
#include <kernel/FS/TmpFS/Inode.h>
|
||||
#include <kernel/Process.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Process;
|
||||
|
||||
class ProcPidInode final : public TmpDirectoryInode
|
||||
{
|
||||
// FIXME: dynamically update ruid/rgid.
|
||||
|
||||
@@ -10,21 +10,6 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
// IDT entries
|
||||
// 0x00->0x1F (32): ISR
|
||||
// 0x20->0x7F (96): PIC/IOAPIC
|
||||
// 0x80->0xEF (112): MSI
|
||||
// 0xF0->0xFE (15): internal
|
||||
|
||||
constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
|
||||
constexpr uint8_t IRQ_MSI_BASE = 0x80;
|
||||
constexpr uint8_t IRQ_MSI_END = 0xF0;
|
||||
#if ARCH(i686)
|
||||
constexpr uint8_t IRQ_SYSCALL = 0xF0; // hard coded in kernel/API/Syscall.h
|
||||
#endif
|
||||
constexpr uint8_t IRQ_IPI = 0xF1;
|
||||
constexpr uint8_t IRQ_TIMER = 0xF2;
|
||||
|
||||
#if ARCH(x86_64)
|
||||
struct GateDescriptor
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace Kernel::Input
|
||||
uint8_t m_byte_index { 0 };
|
||||
bool m_basic { false };
|
||||
|
||||
bool m_scancode_set_uncertain { false };
|
||||
uint8_t m_scancode_set { 0xFF };
|
||||
uint16_t m_modifiers { 0 };
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Arch.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
// IDT entries
|
||||
// 0x00->0x1F (32): ISR
|
||||
// 0x20->0x7F (96): PIC/IOAPIC
|
||||
// 0x80->0xEF (112): MSI
|
||||
// 0xF0->0xFE (15): internal
|
||||
|
||||
constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
|
||||
constexpr uint8_t IRQ_MSI_BASE = 0x80;
|
||||
constexpr uint8_t IRQ_MSI_END = 0xF0;
|
||||
#if ARCH(i686)
|
||||
constexpr uint8_t IRQ_SYSCALL = 0xF0; // hard coded in kernel/API/Syscall.h
|
||||
#endif
|
||||
constexpr uint8_t IRQ_IPI = 0xF1;
|
||||
constexpr uint8_t IRQ_TIMER = 0xF2;
|
||||
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -27,63 +26,14 @@ namespace Kernel
|
||||
public:
|
||||
Mutex() = default;
|
||||
|
||||
void lock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||
pid_t expected = -1;
|
||||
while (!m_locker.compare_exchange(expected, tid))
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||
Processor::yield();
|
||||
expected = -1;
|
||||
}
|
||||
ASSERT(m_lock_depth == 0);
|
||||
if (tid)
|
||||
Thread::current().add_mutex();
|
||||
}
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
pid_t expected = -1;
|
||||
if (!m_locker.compare_exchange(expected, tid))
|
||||
return false;
|
||||
ASSERT(m_lock_depth == 0);
|
||||
if (tid)
|
||||
Thread::current().add_mutex();
|
||||
}
|
||||
m_lock_depth++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(m_locker == tid);
|
||||
ASSERT(m_lock_depth > 0);
|
||||
if (--m_lock_depth == 0)
|
||||
{
|
||||
m_locker = -1;
|
||||
if (tid)
|
||||
Thread::current().remove_mutex();
|
||||
}
|
||||
}
|
||||
bool try_lock();
|
||||
void lock() override;
|
||||
void unlock() override;
|
||||
|
||||
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 override { return m_locker == Thread::current_tid(); }
|
||||
bool is_locked_by_current_thread() const override;
|
||||
|
||||
private:
|
||||
BAN::Atomic<pid_t> m_locker { -1 };
|
||||
@@ -98,74 +48,14 @@ namespace Kernel
|
||||
public:
|
||||
PriorityMutex() = default;
|
||||
|
||||
void lock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||
if (has_priority)
|
||||
m_queue_length++;
|
||||
pid_t expected = -1;
|
||||
while (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||
Processor::yield();
|
||||
expected = -1;
|
||||
}
|
||||
ASSERT(m_lock_depth == 0);
|
||||
if (tid)
|
||||
Thread::current().add_mutex();
|
||||
}
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||
pid_t expected = -1;
|
||||
if (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
|
||||
return false;
|
||||
if (has_priority)
|
||||
m_queue_length++;
|
||||
ASSERT(m_lock_depth == 0);
|
||||
if (tid)
|
||||
Thread::current().add_mutex();
|
||||
}
|
||||
m_lock_depth++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock() override
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(m_locker == tid);
|
||||
ASSERT(m_lock_depth > 0);
|
||||
if (--m_lock_depth == 0)
|
||||
{
|
||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||
if (has_priority)
|
||||
m_queue_length--;
|
||||
m_locker = -1;
|
||||
if (tid)
|
||||
Thread::current().remove_mutex();
|
||||
}
|
||||
}
|
||||
bool try_lock();
|
||||
void lock() override;
|
||||
void unlock() override;
|
||||
|
||||
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 override { return m_locker == Thread::current_tid(); }
|
||||
bool is_locked_by_current_thread() const override;
|
||||
|
||||
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/ThreadBlocker.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
@@ -13,54 +13,10 @@ namespace Kernel
|
||||
public:
|
||||
RWLock() = default;
|
||||
|
||||
void rd_lock()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
while (m_writers_waiting > 0 || m_writer != -1)
|
||||
{
|
||||
BlockableSpinLock block(m_lock);
|
||||
m_thread_blocker.block_indefinite(&block);
|
||||
}
|
||||
m_readers_active++;
|
||||
}
|
||||
|
||||
void rd_unlock()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
if (--m_readers_active == 0)
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
|
||||
void wr_lock()
|
||||
{
|
||||
if (m_writer == Thread::current_tid())
|
||||
{
|
||||
m_writer_depth++;
|
||||
return;
|
||||
}
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
m_writers_waiting++;
|
||||
while (m_readers_active > 0 || m_writer != -1)
|
||||
{
|
||||
BlockableSpinLock block(m_lock);
|
||||
m_thread_blocker.block_indefinite(&block);
|
||||
}
|
||||
m_writers_waiting--;
|
||||
|
||||
m_writer = Thread::current_tid();
|
||||
m_writer_depth = 1;
|
||||
}
|
||||
|
||||
void wr_unlock()
|
||||
{
|
||||
if (--m_writer_depth != 0)
|
||||
return;
|
||||
SpinLockGuard _(m_lock);
|
||||
m_writer = -1;
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
void rd_lock();
|
||||
void rd_unlock();
|
||||
void wr_lock();
|
||||
void wr_unlock();
|
||||
|
||||
private:
|
||||
SpinLock m_lock;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/Memory/MemoryRegion.h>
|
||||
|
||||
namespace Kernel
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/HashMap.h>
|
||||
#include <BAN/RefPtr.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
#include <kernel/Memory/MemoryRegion.h>
|
||||
@@ -27,8 +29,9 @@ namespace Kernel
|
||||
private:
|
||||
struct Object : public BAN::RefCounted<Object>
|
||||
{
|
||||
Object(key_t key, shmid_ds info)
|
||||
Object(key_t key, int id, shmid_ds info)
|
||||
: key(key)
|
||||
, id(id)
|
||||
, info(info)
|
||||
{ }
|
||||
~Object();
|
||||
@@ -36,6 +39,7 @@ namespace Kernel
|
||||
bool can_current_process_access(int flags) const;
|
||||
|
||||
const key_t key;
|
||||
const int id;
|
||||
shmid_ds info;
|
||||
|
||||
Mutex mutex;
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include <BAN/HashMap.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
#include <kernel/Networking/NetworkLayer.h>
|
||||
#include <kernel/Networking/NetworkSocket.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
#include <kernel/Memory/VirtualRange.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <kernel/Memory/ByteRingBuffer.h>
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
#include <kernel/Networking/NetworkSocket.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
|
||||
namespace Kernel
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <kernel/FS/Socket.h>
|
||||
#include <kernel/FS/TmpFS/Inode.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/Memory/VirtualRange.h>
|
||||
#include <kernel/OpenFileDescriptorSet.h>
|
||||
|
||||
namespace Kernel
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/InterruptNumbers.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <poll.h>
|
||||
#include <sys/banan-os.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -26,8 +27,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <termios.h>
|
||||
|
||||
struct epoll_event;
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Array.h>
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/ForwardList.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <BAN/Math.h>
|
||||
|
||||
#include <kernel/API/SharedPage.h>
|
||||
#include <kernel/Arch.h>
|
||||
#include <kernel/GDT.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptStack.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
#include <kernel/ProcessorID.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
@@ -22,6 +19,12 @@ namespace Kernel
|
||||
Enabled,
|
||||
};
|
||||
|
||||
class GDT;
|
||||
class IDT;
|
||||
class Scheduler;
|
||||
class SchedulerThreadNode;
|
||||
class Thread;
|
||||
|
||||
#if ARCH(x86_64) || ARCH(i686)
|
||||
class Processor
|
||||
{
|
||||
@@ -51,8 +54,8 @@ namespace Kernel
|
||||
union
|
||||
{
|
||||
TLBEntry flush_tlb;
|
||||
SchedulerQueue::Node* new_thread;
|
||||
SchedulerQueue::Node* unblock_thread;
|
||||
SchedulerThreadNode* new_thread;
|
||||
SchedulerThreadNode* unblock_thread;
|
||||
bool dummy;
|
||||
};
|
||||
};
|
||||
@@ -179,16 +182,22 @@ namespace Kernel
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8 && BAN::Math::is_power_of_two(sizeof(T)))
|
||||
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= sizeof(uintptr_t) && BAN::Math::is_power_of_two(sizeof(T)))
|
||||
{
|
||||
T value;
|
||||
asm volatile("mov %%gs:%a[offset], %[value]" : [value]"=r"(value) : [offset]"ir"(offset));
|
||||
if constexpr (sizeof(T) == 1 && ARCH(i686))
|
||||
asm volatile("mov %%gs:%a[offset], %[value]" : [value]"=q"(value) : [offset]"ir"(offset) : "memory");
|
||||
else
|
||||
asm volatile("mov %%gs:%a[offset], %[value]" : [value]"=r"(value) : [offset]"ir"(offset) : "memory");
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void write_gs_sized(uintptr_t offset, T value) requires(sizeof(T) <= 8 && BAN::Math::is_power_of_two(sizeof(T)))
|
||||
static void write_gs_sized(uintptr_t offset, T value) requires(sizeof(T) <= sizeof(uintptr_t) && BAN::Math::is_power_of_two(sizeof(T)))
|
||||
{
|
||||
if constexpr (sizeof(T) == 1 && ARCH(i686))
|
||||
asm volatile("mov %[value], %%gs:%a[offset]" :: [value]"q"(value), [offset]"ir"(offset) : "memory");
|
||||
else
|
||||
asm volatile("mov %[value], %%gs:%a[offset]" :: [value]"r"(value), [offset]"ir"(offset) : "memory");
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <kernel/InterruptStack.h>
|
||||
#include <kernel/ProcessorID.h>
|
||||
#include <kernel/SchedulerThreadNode.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -14,29 +15,6 @@ namespace Kernel
|
||||
class BaseMutex;
|
||||
class Thread;
|
||||
class ThreadBlocker;
|
||||
struct SchedulerQueueNode;
|
||||
|
||||
class SchedulerQueue
|
||||
{
|
||||
public:
|
||||
using Node = SchedulerQueueNode;
|
||||
|
||||
public:
|
||||
void add_thread_to_back(Node*);
|
||||
bool add_thread_with_wake_time(Node*); // return true if node was inserted as the first element
|
||||
template<typename F>
|
||||
Node* remove_with_condition(F callback);
|
||||
void remove_node(Node*);
|
||||
Node* front();
|
||||
Node* pop_front();
|
||||
|
||||
bool empty() const { return m_head == nullptr; }
|
||||
|
||||
private:
|
||||
Node* m_head { nullptr };
|
||||
Node* m_tail { nullptr };
|
||||
};
|
||||
|
||||
class Scheduler
|
||||
{
|
||||
BAN_NON_COPYABLE(Scheduler);
|
||||
@@ -45,12 +23,12 @@ namespace Kernel
|
||||
public:
|
||||
struct NewThreadRequest
|
||||
{
|
||||
SchedulerQueue::Node* node;
|
||||
SchedulerThreadNode* node;
|
||||
};
|
||||
|
||||
struct UnblockRequest
|
||||
{
|
||||
SchedulerQueue::Node* node;
|
||||
SchedulerThreadNode* node;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -79,9 +57,9 @@ namespace Kernel
|
||||
private:
|
||||
Scheduler() = default;
|
||||
|
||||
void add_current_to_most_loaded(SchedulerQueue* target_queue);
|
||||
void update_most_loaded_node_queue(SchedulerQueue::Node*, SchedulerQueue* target_queue);
|
||||
void remove_node_from_most_loaded(SchedulerQueue::Node*);
|
||||
void add_current_to_most_loaded(void* target_list);
|
||||
void update_most_loaded_node_list(SchedulerThreadNode*, void* target_list);
|
||||
void remove_node_from_most_loaded(SchedulerThreadNode*);
|
||||
|
||||
void update_wake_up_deadline();
|
||||
void wake_up_sleeping_threads();
|
||||
@@ -90,13 +68,13 @@ namespace Kernel
|
||||
|
||||
class ProcessorID find_least_loaded_processor() const;
|
||||
|
||||
void add_thread(SchedulerQueue::Node*);
|
||||
void unblock_thread(SchedulerQueue::Node*);
|
||||
void add_thread(SchedulerThreadNode*);
|
||||
void unblock_thread(SchedulerThreadNode*);
|
||||
|
||||
private:
|
||||
SchedulerQueue m_run_queue;
|
||||
SchedulerQueue m_block_queue;
|
||||
SchedulerQueue::Node* m_current { nullptr };
|
||||
SchedulerQueue m_run_list;
|
||||
SchedulerHeap m_block_list;
|
||||
SchedulerThreadNode* m_current { nullptr };
|
||||
|
||||
uint32_t m_thread_count { 0 };
|
||||
|
||||
@@ -108,8 +86,8 @@ namespace Kernel
|
||||
|
||||
struct ThreadInfo
|
||||
{
|
||||
SchedulerQueue* queue { nullptr };
|
||||
SchedulerQueue::Node* node { nullptr };
|
||||
void* list { nullptr };
|
||||
SchedulerThreadNode* node { nullptr };
|
||||
};
|
||||
BAN::Array<ThreadInfo, 10> m_most_loaded_threads;
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ProcessorID.h>
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Thread;
|
||||
class ThreadBlocker;
|
||||
|
||||
struct SchedulerQueueNode
|
||||
{
|
||||
SchedulerQueueNode(Thread* thread)
|
||||
: thread(thread)
|
||||
{}
|
||||
|
||||
Thread* const thread;
|
||||
|
||||
SchedulerQueueNode* next { nullptr };
|
||||
SchedulerQueueNode* prev { nullptr };
|
||||
|
||||
uint64_t wake_time_ns { static_cast<uint64_t>(-1) };
|
||||
|
||||
BAN::Atomic<ThreadBlocker*> blocker { nullptr };
|
||||
SchedulerQueueNode* block_chain_prev { nullptr };
|
||||
SchedulerQueueNode* block_chain_next { nullptr };
|
||||
|
||||
ProcessorID processor_id { PROCESSOR_NONE };
|
||||
bool blocked { false };
|
||||
|
||||
uint64_t last_start_ns { 0 };
|
||||
uint64_t time_used_ns { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <kernel/ProcessorID.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Thread;
|
||||
class ThreadBlocker;
|
||||
|
||||
struct SchedulerThreadNode
|
||||
{
|
||||
SchedulerThreadNode(Thread* thread)
|
||||
: thread(thread)
|
||||
, heap({ nullptr, nullptr, nullptr })
|
||||
{}
|
||||
|
||||
Thread* const thread;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
SchedulerThreadNode* next;
|
||||
SchedulerThreadNode* prev;
|
||||
} queue;
|
||||
struct
|
||||
{
|
||||
SchedulerThreadNode* parent;
|
||||
SchedulerThreadNode* lchild;
|
||||
SchedulerThreadNode* rchild;
|
||||
} heap;
|
||||
};
|
||||
|
||||
uint64_t wake_time_ns { static_cast<uint64_t>(-1) };
|
||||
|
||||
BAN::Atomic<ThreadBlocker*> blocker { nullptr };
|
||||
SchedulerThreadNode* block_chain_prev { nullptr };
|
||||
SchedulerThreadNode* block_chain_next { nullptr };
|
||||
|
||||
ProcessorID processor_id { PROCESSOR_NONE };
|
||||
bool blocked { false };
|
||||
|
||||
uint64_t last_start_ns { 0 };
|
||||
uint64_t time_used_ns { 0 };
|
||||
};
|
||||
|
||||
class SchedulerQueue
|
||||
{
|
||||
BAN_NON_COPYABLE(SchedulerQueue);
|
||||
BAN_NON_MOVABLE(SchedulerQueue);
|
||||
public:
|
||||
SchedulerQueue() = default;
|
||||
|
||||
SchedulerThreadNode* front();
|
||||
SchedulerThreadNode* pop_front();
|
||||
|
||||
void push(SchedulerThreadNode*);
|
||||
void pop(SchedulerThreadNode*);
|
||||
|
||||
void walk(void (*)(const SchedulerThreadNode*, void*), void*) const;
|
||||
bool empty() const { return m_head == nullptr; }
|
||||
|
||||
private:
|
||||
SchedulerThreadNode* m_head { nullptr };
|
||||
SchedulerThreadNode* m_tail { nullptr };
|
||||
};
|
||||
|
||||
class SchedulerHeap
|
||||
{
|
||||
BAN_NON_COPYABLE(SchedulerHeap);
|
||||
BAN_NON_MOVABLE(SchedulerHeap);
|
||||
public:
|
||||
SchedulerHeap() = default;
|
||||
|
||||
SchedulerThreadNode* front();
|
||||
SchedulerThreadNode* pop_front();
|
||||
|
||||
void push(SchedulerThreadNode*);
|
||||
void pop(SchedulerThreadNode*);
|
||||
|
||||
void walk(void (*)(const SchedulerThreadNode*, void*), void*) const;
|
||||
bool empty() const { return m_root == nullptr; }
|
||||
|
||||
private:
|
||||
void walk_impl(void (*)(const SchedulerThreadNode*, void*), void*, const SchedulerThreadNode*) const;
|
||||
void swap_nodes(SchedulerThreadNode*, SchedulerThreadNode*);
|
||||
|
||||
private:
|
||||
SchedulerThreadNode* m_root { nullptr };
|
||||
SchedulerThreadNode* m_last { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/WeakPtr.h>
|
||||
#include <kernel/Memory/VirtualRange.h>
|
||||
#include <kernel/Terminal/TTY.h>
|
||||
|
||||
namespace Kernel
|
||||
|
||||
@@ -96,8 +96,6 @@ namespace Kernel
|
||||
uint32_t m_last_cursor_row { static_cast<uint32_t>(-1) };
|
||||
uint32_t m_last_cursor_column { static_cast<uint32_t>(-1) };
|
||||
|
||||
const Palette& m_palette;
|
||||
|
||||
TerminalDriver::Color m_foreground;
|
||||
TerminalDriver::Color m_background;
|
||||
bool m_colors_inverted { false };
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include <BAN/RefPtr.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <kernel/InterruptStack.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Memory/VirtualRange.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
|
||||
#include <LibELF/AuxiliaryVector.h>
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Kernel
|
||||
|
||||
class MemoryBackedRegion;
|
||||
class Process;
|
||||
class ThreadBlocker;
|
||||
|
||||
class Thread
|
||||
{
|
||||
@@ -124,10 +125,14 @@ namespace Kernel
|
||||
|
||||
bool is_userspace() const { return m_is_userspace; }
|
||||
|
||||
uint64_t cpu_time_ns() const;
|
||||
uint64_t cpu_time_total_ns() const;
|
||||
void cpu_time_ns(uint64_t& user_ns, uint64_t& system_ns) const;
|
||||
void set_cpu_time_start();
|
||||
void set_cpu_time_stop();
|
||||
|
||||
void set_is_in_syscall(bool is_in_syscall);
|
||||
bool is_in_syscall() const { return m_is_in_syscall; }
|
||||
|
||||
void update_processor_index_address();
|
||||
|
||||
void set_fsbase(vaddr_t base) { m_fsbase = base; }
|
||||
@@ -187,7 +192,7 @@ namespace Kernel
|
||||
vaddr_t m_fsbase { 0 };
|
||||
vaddr_t m_gsbase { 0 };
|
||||
|
||||
SchedulerQueue::Node* m_scheduler_node { nullptr };
|
||||
SchedulerThreadNode* m_scheduler_node { nullptr };
|
||||
|
||||
YieldRegisters m_yield_registers { };
|
||||
|
||||
@@ -200,8 +205,10 @@ namespace Kernel
|
||||
static_assert(_SIGMAX < 64);
|
||||
|
||||
mutable SpinLock m_cpu_time_lock;
|
||||
uint64_t m_cpu_time_ns { 0 };
|
||||
uint64_t m_cpu_time_user_ns { 0 };
|
||||
uint64_t m_cpu_time_system_ns { 0 };
|
||||
uint64_t m_cpu_time_start_ns { UINT64_MAX };
|
||||
BAN::Atomic<bool> m_is_in_syscall { false };
|
||||
|
||||
BAN::Atomic<uint32_t> m_spinlock_count { 0 };
|
||||
BAN::Atomic<uint32_t> m_mutex_count { 0 };
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Math.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class SchedulerThreadNode;
|
||||
|
||||
class ThreadBlocker
|
||||
{
|
||||
public:
|
||||
@@ -27,11 +29,11 @@ namespace Kernel
|
||||
}
|
||||
|
||||
private:
|
||||
void add_thread_to_block_queue(SchedulerQueue::Node*);
|
||||
void remove_thread_from_block_queue(SchedulerQueue::Node*);
|
||||
void add_thread_to_block_queue(SchedulerThreadNode*);
|
||||
void remove_thread_from_block_queue(SchedulerThreadNode*);
|
||||
|
||||
private:
|
||||
SchedulerQueue::Node* m_block_chain { nullptr };
|
||||
SchedulerThreadNode* m_block_chain { nullptr };
|
||||
SpinLock m_lock;
|
||||
|
||||
friend class Scheduler;
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace Kernel
|
||||
|
||||
virtual void handle_stall(uint8_t endpoint_id) = 0;
|
||||
virtual void handle_input_data(size_t byte_count, uint8_t endpoint_id) = 0;
|
||||
|
||||
virtual bool is_hid_driver() const { return false; }
|
||||
};
|
||||
|
||||
class USBDevice
|
||||
@@ -62,6 +64,12 @@ namespace Kernel
|
||||
uint8_t tt_think_time;
|
||||
};
|
||||
|
||||
struct HIDInfo
|
||||
{
|
||||
BAN::Atomic<uint32_t> led_mask { 0 };
|
||||
BAN::Vector<USBClassDriver*> led_controls;
|
||||
};
|
||||
|
||||
public:
|
||||
USBDevice(USBController& controller, USB::SpeedClass speed_class, uint8_t depth)
|
||||
: m_controller(controller)
|
||||
@@ -92,6 +100,8 @@ namespace Kernel
|
||||
void register_hub_to_init() { m_controller.register_hub_to_init(m_depth + 1); };
|
||||
void mark_hub_init_done() { m_controller.mark_hub_init_done(m_depth + 1); };
|
||||
|
||||
void update_led_mask(uint32_t led_mask);
|
||||
|
||||
protected:
|
||||
void handle_stall(uint8_t endpoint_id);
|
||||
void handle_input_data(size_t byte_count, uint8_t endpoint_id);
|
||||
@@ -112,6 +122,7 @@ namespace Kernel
|
||||
BAN::UniqPtr<DMARegion> m_dma_buffer;
|
||||
|
||||
BAN::Vector<BAN::UniqPtr<USBClassDriver>> m_class_drivers;
|
||||
HIDInfo m_hid_info;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ namespace Kernel
|
||||
struct DeviceReport
|
||||
{
|
||||
BAN::Vector<USBHID::Report> inputs;
|
||||
BAN::Vector<USBHID::Report> outputs;
|
||||
BAN::RefPtr<USBHIDDevice> device;
|
||||
};
|
||||
|
||||
@@ -81,27 +82,43 @@ namespace Kernel
|
||||
void handle_stall(uint8_t endpoint_id) override;
|
||||
void handle_input_data(size_t byte_count, uint8_t endpoint_id) override;
|
||||
|
||||
bool is_hid_driver() const override { return true; }
|
||||
|
||||
USBDevice& device() { return m_device; }
|
||||
const USBDevice::InterfaceDescriptor& interface() const { return m_interface; }
|
||||
|
||||
bool has_led_control() const { return !m_led_controls.empty(); }
|
||||
void set_leds(uint32_t led_mask);
|
||||
|
||||
private:
|
||||
USBHIDDriver(USBDevice&, const USBDevice::InterfaceDescriptor&);
|
||||
~USBHIDDriver();
|
||||
|
||||
BAN::ErrorOr<void> initialize() override;
|
||||
|
||||
BAN::ErrorOr<BAN::Vector<DeviceReport>> initializes_device_reports(const BAN::Vector<USBHID::Collection>&);
|
||||
BAN::ErrorOr<void> initializes_device_reports(const BAN::Vector<USBHID::Collection>&);
|
||||
|
||||
private:
|
||||
struct LEDControl
|
||||
{
|
||||
DeviceReport* report;
|
||||
uint32_t report_id;
|
||||
uint32_t report_bits;
|
||||
};
|
||||
|
||||
private:
|
||||
USBDevice& m_device;
|
||||
USBDevice::InterfaceDescriptor m_interface;
|
||||
|
||||
bool m_uses_report_id { false };
|
||||
BAN::Vector<DeviceReport> m_device_inputs;
|
||||
BAN::Vector<DeviceReport> m_device_reports;
|
||||
|
||||
uint8_t m_data_endpoint_id = 0;
|
||||
BAN::UniqPtr<DMARegion> m_data_buffer;
|
||||
|
||||
BAN::Vector<LEDControl> m_led_controls;
|
||||
BAN::UniqPtr<DMARegion> m_led_region;
|
||||
|
||||
friend class BAN::UniqPtr<USBHIDDriver>;
|
||||
};
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ namespace Kernel
|
||||
BAN_NON_MOVABLE(USBKeyboard);
|
||||
|
||||
public:
|
||||
BAN::ErrorOr<void> initialize() override;
|
||||
|
||||
void start_report() override;
|
||||
void stop_report() override;
|
||||
|
||||
@@ -23,12 +21,9 @@ namespace Kernel
|
||||
void update() override;
|
||||
|
||||
private:
|
||||
USBKeyboard(USBHIDDriver& driver, BAN::Vector<USBHID::Report>&& outputs);
|
||||
USBKeyboard(USBHIDDriver& driver);
|
||||
~USBKeyboard() = default;
|
||||
|
||||
void set_leds(uint16_t mask);
|
||||
void set_leds(uint8_t report_id, uint16_t mask);
|
||||
|
||||
private:
|
||||
USBHIDDriver& m_driver;
|
||||
|
||||
@@ -38,11 +33,7 @@ namespace Kernel
|
||||
BAN::Array<bool, 0x100> m_keyboard_state { false };
|
||||
BAN::Array<bool, 0x100> m_keyboard_state_temp { false };
|
||||
uint16_t m_toggle_mask { 0 };
|
||||
|
||||
uint16_t m_led_mask { 0 };
|
||||
BAN::UniqPtr<DMARegion> m_led_region;
|
||||
|
||||
BAN::Vector<USBHID::Report> m_outputs;
|
||||
|
||||
BAN::Optional<uint8_t> m_repeat_scancode;
|
||||
uint8_t m_repeat_modifier { 0 };
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/USB/Device.h>
|
||||
|
||||
namespace Kernel
|
||||
|
||||
@@ -373,6 +373,33 @@ namespace Kernel::XHCI
|
||||
uint32_t slot_id : 8;
|
||||
} configure_endpoint_command;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t : 32;
|
||||
uint32_t : 32;
|
||||
uint32_t : 32;
|
||||
uint32_t cycle_bit : 1;
|
||||
uint32_t : 8;
|
||||
uint32_t tsp : 1;
|
||||
uint32_t trb_type : 6;
|
||||
uint32_t endpoint_id : 5;
|
||||
uint32_t : 3;
|
||||
uint32_t slot_id : 8;
|
||||
} reset_endpoint_command;
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t new_tr_deque_pointer : 64;
|
||||
uint32_t : 16;
|
||||
uint32_t stream_id : 16;
|
||||
uint32_t cycle_bit : 1;
|
||||
uint32_t : 9;
|
||||
uint32_t trb_type : 6;
|
||||
uint32_t endpoint_id : 5;
|
||||
uint32_t : 3;
|
||||
uint32_t slot_id : 8;
|
||||
} set_tr_deque_pointer_command;
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t ring_segment_ponter : 64;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#define RSPD_SIZE 20
|
||||
@@ -789,7 +790,7 @@ acpi_release_global_lock:
|
||||
auto [gpe_path, gpe_obj] = TRY(m_namespace->find_named_object(embedded_controller, TRY(AML::NameString::from_string("_GPE"_sv)), true));
|
||||
if (gpe_obj == nullptr)
|
||||
{
|
||||
dwarnln("EC {} does have _GPE", embedded_controller);
|
||||
dwarnln("EC {} does not have _GPE", embedded_controller);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -806,7 +807,7 @@ acpi_release_global_lock:
|
||||
auto [crs_path, crs_obj] = TRY(m_namespace->find_named_object(embedded_controller, TRY(AML::NameString::from_string("_CRS"_sv)), true));
|
||||
if (crs_obj == nullptr)
|
||||
{
|
||||
dwarnln("EC {} does have _CRS", embedded_controller);
|
||||
dwarnln("EC {} does not have _CRS", embedded_controller);
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
}
|
||||
|
||||
@@ -1198,6 +1199,8 @@ acpi_release_global_lock:
|
||||
continue;
|
||||
|
||||
handle_event:
|
||||
IO::outw(sts_port, pending);
|
||||
|
||||
if (pending & PM1_EVN_PWRBTN)
|
||||
{
|
||||
dprintln("Power button pressed");
|
||||
@@ -1208,8 +1211,6 @@ handle_event:
|
||||
{
|
||||
dwarnln("Unhandled ACPI fixed event {H}", pending);
|
||||
}
|
||||
|
||||
IO::outw(sts_port, pending);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <kernel/ACPI/BatterySystem.h>
|
||||
#include <kernel/FS/DevFS//FileSystem.h>
|
||||
#include <kernel/Device/Device.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
@@ -35,34 +36,11 @@ namespace Kernel::ACPI
|
||||
if (offset < 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
if (SystemTimer::get().ms_since_boot() > m_last_read_ms + 1000)
|
||||
{
|
||||
auto [method_path, method_ref] = TRY(m_acpi_namespace.find_named_object(m_battery_path, m_method_name));
|
||||
if (method_ref == nullptr)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
auto result = TRY(AML::method_call(method_path, method_ref->node, BAN::Array<AML::Reference*, 7>{}));
|
||||
if (result.type != AML::Node::Type::Package || result.as.package->num_elements < m_result_index)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
auto& target_elem = result.as.package->elements[m_result_index];
|
||||
if (!target_elem.resolved || !target_elem.value.node)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
auto target_conv = AML::convert_node(TRY(target_elem.value.node->copy()), AML::ConvInteger, sizeof(uint64_t));
|
||||
if (target_conv.is_error())
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
m_last_read_ms = SystemTimer::get().ms_since_boot();
|
||||
m_last_value = target_conv.value().as.integer.value;
|
||||
}
|
||||
|
||||
auto target_str = TRY(BAN::String::formatted("{}", m_last_value.load()));
|
||||
|
||||
auto target_str = TRY(BAN::String::formatted("{}", TRY(get_value())));
|
||||
if (static_cast<size_t>(offset) >= target_str.size())
|
||||
return 0;
|
||||
|
||||
const size_t ncopy = BAN::Math::min(buffer.size(), target_str.size() - offset);
|
||||
const size_t ncopy = BAN::Math::min<size_t>(buffer.size(), target_str.size() - offset);
|
||||
memcpy(buffer.data(), target_str.data() + offset, ncopy);
|
||||
return ncopy;
|
||||
}
|
||||
@@ -84,14 +62,44 @@ namespace Kernel::ACPI
|
||||
, m_result_index(index)
|
||||
{ }
|
||||
|
||||
BAN::ErrorOr<uint64_t> get_value()
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
if (SystemTimer::get().ms_since_boot() < m_last_read_ms + 1000)
|
||||
return m_last_value;
|
||||
|
||||
auto [method_path, method_ref] = TRY(m_acpi_namespace.find_named_object(m_battery_path, m_method_name));
|
||||
if (method_ref == nullptr)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
auto result = TRY(AML::method_call(method_path, method_ref->node, BAN::Array<AML::Reference*, 7>{}));
|
||||
if (result.type != AML::Node::Type::Package || result.as.package->num_elements < m_result_index)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
auto& target_elem = result.as.package->elements[m_result_index];
|
||||
if (!target_elem.resolved || !target_elem.value.node)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
auto target_conv = AML::convert_node(TRY(target_elem.value.node->copy()), AML::ConvInteger, sizeof(uint64_t));
|
||||
if (target_conv.is_error())
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
m_last_read_ms = SystemTimer::get().ms_since_boot();
|
||||
m_last_value = target_conv.value().as.integer.value;
|
||||
|
||||
return m_last_value;
|
||||
}
|
||||
|
||||
private:
|
||||
AML::Namespace& m_acpi_namespace;
|
||||
AML::Scope m_battery_path;
|
||||
AML::NameString m_method_name;
|
||||
size_t m_result_index;
|
||||
|
||||
BAN::Atomic<uint64_t> m_last_read_ms = 0;
|
||||
BAN::Atomic<uint64_t> m_last_value = 0;
|
||||
Mutex m_mutex;
|
||||
uint64_t m_last_read_ms = 0;
|
||||
uint64_t m_last_value = 0;
|
||||
};
|
||||
|
||||
BAN::ErrorOr<void> BatterySystem::initialize(AML::Namespace& acpi_namespace)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <kernel/ACPI/EmbeddedController.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
|
||||
@@ -351,17 +351,17 @@ namespace Kernel
|
||||
// give processor upto 100 * 100 us + 200 us to boot
|
||||
PageTable::with_fast_page(ap_init_paddr, [&] {
|
||||
for (int i = 0; i < 100; i++, udelay(100))
|
||||
if (__atomic_load_n(&PageTable::fast_page_as<ap_init_info_t>(8).ready, __ATOMIC_SEQ_CST))
|
||||
if (BAN::atomic_load(PageTable::fast_page_as<ap_init_info_t>(8).ready))
|
||||
break;
|
||||
});
|
||||
|
||||
initialized_aps++;
|
||||
}
|
||||
|
||||
__atomic_store_n(&g_ap_startup_done[0], 1, __ATOMIC_SEQ_CST);
|
||||
BAN::atomic_store(g_ap_startup_done[0], 1);
|
||||
|
||||
const size_t timeout_ms = SystemTimer::get().ms_since_boot() + 500;
|
||||
while (__atomic_load_n(&g_ap_running_count[0], __ATOMIC_SEQ_CST) < initialized_aps)
|
||||
while (BAN::atomic_load(g_ap_running_count[0]) < initialized_aps)
|
||||
{
|
||||
if (SystemTimer::get().ms_since_boot() >= timeout_ms)
|
||||
Kernel::panic("Could not start all APs ({}/{} started)", g_ap_running_count[0], initialized_aps);
|
||||
@@ -511,9 +511,12 @@ namespace Kernel
|
||||
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2);
|
||||
redir.hi_dword = ioapic->read(IOAPIC_REDIRS + pin * 2 + 1);
|
||||
|
||||
redir.trigger_mode = level_triggered;
|
||||
redir.vector = IRQ_VECTOR_BASE + irq;
|
||||
redir.delivery_mode = 0; // fixed
|
||||
redir.pin_polarity = 0; // active high
|
||||
redir.trigger_mode = level_triggered;
|
||||
redir.mask = 0;
|
||||
redir.destination_mode = 0; // physical
|
||||
// FIXME: distribute IRQs more evenly?
|
||||
redir.destination = Kernel::Processor::bsp_id().as_u32();
|
||||
|
||||
|
||||
@@ -224,7 +224,12 @@ namespace Kernel
|
||||
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());
|
||||
|
||||
const uint32_t volume_data = get_volume_data();
|
||||
m_mixer->write16(AudioMixerRegister::MasterVolume, volume_data);
|
||||
|
||||
m_volume_info.mdB = -(volume_data & 0xFF) * m_volume_info.step_mdB;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Lock/BlockableSpinLock.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
@@ -139,31 +139,27 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<void> HDAudioFunctionGroup::set_volume_mdB(int32_t mdB)
|
||||
{
|
||||
if (m_amplifier_idx == SIZE_MAX)
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
|
||||
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 auto* node = m_output_paths[m_output_path_index][m_amplifier_idx];
|
||||
|
||||
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 step = (mdB + step_round) / m_volume_info.step_mdB + node->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,
|
||||
.node_index = node->id,
|
||||
.codec_address = m_cid,
|
||||
}));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
m_volume_info.mdB = mdB;
|
||||
m_volume_info.mdB = (mdB + step_round) / m_volume_info.step_mdB * m_volume_info.step_mdB;
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -331,8 +327,8 @@ namespace Kernel
|
||||
uint16_t HDAudioFunctionGroup::get_format_data() const
|
||||
{
|
||||
// TODO: don't hardcode this
|
||||
// format: PCM, 48 kHz, 16 bit, 2 channels
|
||||
return 0b0'0'000'000'0'001'0001;
|
||||
// format: PCM, 48 kHz, 16 bit
|
||||
return 0b0'0'000'000'0'001'0000 | (get_channels() - 1);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
|
||||
@@ -346,6 +342,7 @@ namespace Kernel
|
||||
{
|
||||
using HDAudio::AFGWidget;
|
||||
case AFGWidget::Type::OutputConverter:
|
||||
case AFGWidget::Type::Mixer:
|
||||
case AFGWidget::Type::PinComplex:
|
||||
break;
|
||||
default:
|
||||
@@ -367,7 +364,7 @@ namespace Kernel
|
||||
}));
|
||||
|
||||
// set connection index
|
||||
if (i + 1 < path.size() && path[i]->connections.size() > 1)
|
||||
if (i + 1 < path.size() && path[i]->connections.size() > 1 && path[i]->type != HDAudio::AFGWidget::Type::Mixer)
|
||||
{
|
||||
uint8_t index = 0;
|
||||
for (; index < path[i]->connections.size(); index++)
|
||||
@@ -407,6 +404,13 @@ namespace Kernel
|
||||
.node_index = path[i]->id,
|
||||
.codec_address = m_cid,
|
||||
}));
|
||||
// set channel count
|
||||
TRY(m_controller->send_command({
|
||||
.data = static_cast<uint8_t>(get_channels() - 1),
|
||||
.command = 0x72D,
|
||||
.node_index = path[i]->id,
|
||||
.codec_address = m_cid,
|
||||
}));
|
||||
// set format
|
||||
TRY(m_controller->send_command({
|
||||
.data = static_cast<uint8_t>(format & 0xFF),
|
||||
@@ -416,6 +420,25 @@ namespace Kernel
|
||||
}));
|
||||
break;
|
||||
|
||||
case AFGWidget::Type::Mixer:
|
||||
if (path[i]->input_amplifier.has_value())
|
||||
{
|
||||
for (size_t idx = 0; idx < path[i]->connections.size(); idx++)
|
||||
{
|
||||
const uint8_t step = (path[i]->connections[idx] == path[i + 1]->id)
|
||||
? path[i]->input_amplifier->offset
|
||||
: 0b1'0000000;
|
||||
const uint32_t volume = 0b0'1'1'1'0000'0'0000000 | (idx << 8) | 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;
|
||||
|
||||
case AFGWidget::Type::PinComplex:
|
||||
// enable output and H-Phn
|
||||
TRY(m_controller->send_command({
|
||||
@@ -438,15 +461,25 @@ 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;
|
||||
int32_t max_steps { 0 };
|
||||
m_amplifier_idx = SIZE_MAX;
|
||||
|
||||
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();
|
||||
if (auto steps = path[i]->output_amplifier->num_steps; steps > max_steps)
|
||||
{
|
||||
max_steps = steps;
|
||||
m_amplifier_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_amplifier_idx == SIZE_MAX)
|
||||
m_volume_info = {};
|
||||
else
|
||||
{
|
||||
const auto& amp = path[m_amplifier_idx]->output_amplifier.value();
|
||||
|
||||
const int32_t step_mdB = (amp.step_size + 1) * 250;
|
||||
m_volume_info.step_mdB = step_mdB;
|
||||
@@ -463,16 +496,11 @@ namespace Kernel
|
||||
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,
|
||||
.node_index = path[m_amplifier_idx]->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 {};
|
||||
}
|
||||
|
||||
@@ -496,6 +524,7 @@ namespace Kernel
|
||||
using HDAudio::AFGWidget;
|
||||
|
||||
case AFGWidget::Type::OutputConverter:
|
||||
case AFGWidget::Type::Mixer:
|
||||
break;
|
||||
|
||||
case AFGWidget::Type::PinComplex:
|
||||
@@ -635,11 +664,8 @@ namespace Kernel
|
||||
m_bdl_tail = (m_bdl_tail + 1) % m_bdl_entry_count;
|
||||
if (m_bdl_tail == m_bdl_head)
|
||||
{
|
||||
if (auto ret = reset_stream(); ret.is_error())
|
||||
{
|
||||
dwarnln("failed to reset HDA stream: {}", ret.error());
|
||||
return;
|
||||
}
|
||||
bar.write8(base + Regs::SDCTL, bar.read8(base + Regs::SDCTL) & 0xFD);
|
||||
m_stream_running = false;
|
||||
}
|
||||
|
||||
queue_bdl_data();
|
||||
|
||||
@@ -333,6 +333,20 @@ namespace Kernel
|
||||
};
|
||||
}
|
||||
|
||||
if (const uint32_t in_amp_cap = send_command_or_zero(0xF00, 0x0D))
|
||||
{
|
||||
const uint8_t offset = (in_amp_cap >> 0) & 0x7F;
|
||||
const uint8_t num_steps = (in_amp_cap >> 8) & 0x7F;
|
||||
const uint8_t step_size = (in_amp_cap >> 16) & 0x7F;
|
||||
const bool mute = (in_amp_cap >> 31);
|
||||
result.input_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;
|
||||
|
||||
+14
-1
@@ -14,6 +14,8 @@
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
#include <kernel/UserCopy.h>
|
||||
|
||||
#if ARCH(x86_64)
|
||||
|
||||
using namespace LibELF;
|
||||
using namespace Kernel;
|
||||
|
||||
@@ -204,7 +206,7 @@ BAN::ErrorOr<size_t> Banos::load_driver_from_image(const char* u_image) {
|
||||
// NOTE: should be more than plenty ;)
|
||||
extern char g_drv_builtin_begin[];
|
||||
extern char g_drv_builtin_end[];
|
||||
void Banos::initialize_initial_drivers(void) {
|
||||
void Banos::initialize_initial_drivers() {
|
||||
import_symbols(g_banos_export, g_banos_export_end - g_banos_export);
|
||||
char* head = g_drv_builtin_begin;
|
||||
while(head < g_drv_builtin_end) {
|
||||
@@ -213,3 +215,14 @@ void Banos::initialize_initial_drivers(void) {
|
||||
head += drv->driver_size;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
void Banos::initialize_initial_drivers()
|
||||
{
|
||||
}
|
||||
BAN::ErrorOr<size_t> Banos::load_driver_from_image(const char* u_image)
|
||||
{
|
||||
(void)u_image;
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <kernel/Epoll.h>
|
||||
#include <kernel/Lock/BlockableSpinLock.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <kernel/FS/EventFD.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
@@ -43,7 +44,7 @@ namespace Kernel
|
||||
while (m_value == 0)
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
|
||||
|
||||
const uint64_t read_value = m_is_semaphore ? 1 : m_value.load();
|
||||
const uint64_t read_value = m_is_semaphore ? 1 : m_value;
|
||||
m_value -= read_value;
|
||||
|
||||
buffer.as<uint64_t>() = read_value;
|
||||
@@ -79,4 +80,16 @@ namespace Kernel
|
||||
return sizeof(uint64_t);
|
||||
}
|
||||
|
||||
bool EventFD::can_read_impl() const
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
return m_value > 0;
|
||||
}
|
||||
|
||||
bool EventFD::can_write_impl() const
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
return m_value < UINT64_MAX - 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <BAN/Sort.h>
|
||||
#include <kernel/FS/Ext2/FileSystem.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
#define EXT2_DEBUG_PRINT 0
|
||||
#define EXT2_VERIFY_INODE 0
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <kernel/Device/Device.h>
|
||||
#include <kernel/FS/FAT/FileSystem.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
|
||||
@@ -123,18 +124,6 @@ namespace Kernel
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
uint32_t block_count = 0;
|
||||
{
|
||||
uint32_t cluster = entry.first_cluster_lo;
|
||||
if (m_type == Type::FAT32)
|
||||
cluster |= static_cast<uint32_t>(entry.first_cluster_hi) << 16;
|
||||
while (cluster >= 2 && cluster < cluster_count())
|
||||
{
|
||||
block_count++;
|
||||
cluster = TRY(get_next_cluster(cluster));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t entry_cluster;
|
||||
switch (m_type)
|
||||
{
|
||||
@@ -143,25 +132,34 @@ namespace Kernel
|
||||
if (parent == m_root_inode)
|
||||
entry_cluster = 1;
|
||||
else
|
||||
{
|
||||
entry_cluster = parent->entry().first_cluster_lo;
|
||||
for (uint32_t i = 0; i < cluster_index; i++)
|
||||
entry_cluster = TRY(get_next_cluster(entry_cluster));
|
||||
}
|
||||
break;
|
||||
case Type::FAT32:
|
||||
if (parent == m_root_inode)
|
||||
entry_cluster = m_bpb.ext_32.root_cluster;
|
||||
else
|
||||
entry_cluster = (static_cast<uint32_t>(parent->entry().first_cluster_hi) << 16) | parent->entry().first_cluster_lo;
|
||||
for (uint32_t i = 0; i < cluster_index; i++)
|
||||
entry_cluster = TRY(get_next_cluster(entry_cluster));
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
const ino_t ino = (static_cast<ino_t>(entry_cluster) << 32) | entry_index;
|
||||
uint32_t block_count = 0;
|
||||
for (uint32_t i = 0; i < cluster_index; i++)
|
||||
{
|
||||
block_count++;
|
||||
entry_cluster = TRY(get_next_cluster(entry_cluster));
|
||||
}
|
||||
|
||||
const uint32_t dirent_per_cluster = m_bpb.bytes_per_sector * m_bpb.sectors_per_cluster / sizeof(FAT::DirectoryEntry);
|
||||
ASSERT(BAN::Math::is_power_of_two(dirent_per_cluster));
|
||||
ASSERT(entry_index < dirent_per_cluster);
|
||||
|
||||
const uint32_t ino_cluster_shift = BAN::Math::ctz(dirent_per_cluster);
|
||||
const ino_t ino = (static_cast<ino_t>(entry_cluster) << ino_cluster_shift) | entry_index;
|
||||
if (ino >> ino_cluster_shift != entry_cluster)
|
||||
dwarnln("FAT ino mapping not unique");
|
||||
|
||||
auto it = m_inode_cache.find(ino);
|
||||
if (it != m_inode_cache.end())
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <BAN/Time.h>
|
||||
|
||||
#include <kernel/Device/Device.h>
|
||||
#include <kernel/FS/FAT/FileSystem.h>
|
||||
#include <kernel/FS/FAT/Inode.h>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <kernel/BootInfo.h>
|
||||
#include <kernel/FS/ProcFS/FileSystem.h>
|
||||
#include <kernel/FS/ProcFS/Inode.h>
|
||||
#include <kernel/Process.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <kernel/FS/ProcFS/Inode.h>
|
||||
#include <kernel/Process.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include <BAN/Array.h>
|
||||
#include <BAN/Errors.h>
|
||||
#include <kernel/GDT.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/InterruptNumbers.h>
|
||||
#include <kernel/InterruptStack.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#include <kernel/Panic.h>
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Input/InputDevice.h>
|
||||
#include <kernel/Lock/BlockableSpinLock.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Terminal/TTY.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
#include <LibInput/Joystick.h>
|
||||
#include <LibInput/KeyEvent.h>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <kernel/Input/PS2/Keyboard.h>
|
||||
#include <kernel/Input/PS2/Mouse.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel::Input
|
||||
@@ -345,7 +347,7 @@ namespace Kernel::Input
|
||||
result.command_port = data->as.fixed_io_port.range_base;
|
||||
break;
|
||||
case ACPI::ResourceData::Type::IRQ:
|
||||
if (__builtin_popcount(data->as.irq.irq_mask) != 1)
|
||||
if (BAN::Math::popcount(data->as.irq.irq_mask) != 1)
|
||||
break;
|
||||
for (int i = 0; i < 16; i++)
|
||||
if (data->as.irq.irq_mask & (1 << i))
|
||||
@@ -386,14 +388,11 @@ namespace Kernel::Input
|
||||
}
|
||||
|
||||
dprintln("Found {} PS/2 devices from ACPI namespace", acpi_devices.size());
|
||||
if (acpi_devices.empty())
|
||||
return {};
|
||||
|
||||
if (acpi_devices.size() > 2)
|
||||
{
|
||||
dwarnln("TODO: over 2 PS/2 devices");
|
||||
while (acpi_devices.size() > 2)
|
||||
acpi_devices.pop_back();
|
||||
MUST(acpi_devices.resize(2));
|
||||
}
|
||||
|
||||
if (acpi_devices.size() == 2)
|
||||
@@ -419,6 +418,8 @@ namespace Kernel::Input
|
||||
}
|
||||
}
|
||||
|
||||
if (!acpi_devices.empty())
|
||||
{
|
||||
BAN::Optional<uint16_t> command_port;
|
||||
command_port = acpi_devices[0].command_port;
|
||||
if (!command_port.has_value() && acpi_devices.size() >= 2)
|
||||
@@ -432,21 +433,20 @@ namespace Kernel::Input
|
||||
data_port = acpi_devices[1].data_port;
|
||||
if (data_port.has_value())
|
||||
m_data_port = data_port.value();
|
||||
}
|
||||
|
||||
devices[0] = {
|
||||
.type = acpi_devices[0].type,
|
||||
.interrupt = acpi_devices[0].irq.value_or(PS2::IRQ::DEVICE0)
|
||||
};
|
||||
|
||||
if (acpi_devices.size() > 1)
|
||||
for (size_t i = 0; i < acpi_devices.size(); i++)
|
||||
{
|
||||
devices[1] = {
|
||||
.type = acpi_devices[1].type,
|
||||
.interrupt = acpi_devices[1].irq.value_or(PS2::IRQ::DEVICE1)
|
||||
devices[i] = {
|
||||
.type = acpi_devices[i].type,
|
||||
.interrupt = acpi_devices[i].irq.value_or(i == 0 ? PS2::IRQ::DEVICE0 : PS2::IRQ::DEVICE1),
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (has_legacy_8042())
|
||||
|
||||
if (devices[0].type != DeviceType::None)
|
||||
;
|
||||
else if (scancode_set || has_legacy_8042())
|
||||
{
|
||||
devices[0] = {
|
||||
.type = DeviceType::Unknown,
|
||||
|
||||
@@ -53,8 +53,9 @@ namespace Kernel::Input
|
||||
|
||||
if (command_data[0] == Command::CONFIG_SCANCODE_SET && m_scancode_set >= 0xFE)
|
||||
{
|
||||
dwarnln("Could not detect scancode set, assuming 2");
|
||||
m_scancode_set = 2;
|
||||
dwarnln("Could not detect scancode set, assuming 1");
|
||||
m_scancode_set_uncertain = true;
|
||||
m_scancode_set = 1;
|
||||
m_keymap.initialize(m_scancode_set);
|
||||
append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0);
|
||||
}
|
||||
@@ -89,6 +90,7 @@ namespace Kernel::Input
|
||||
else
|
||||
{
|
||||
dwarnln("Could not detect scancode set, assuming 1");
|
||||
m_scancode_set_uncertain = true;
|
||||
m_scancode_set = 1;
|
||||
}
|
||||
m_keymap.initialize(m_scancode_set);
|
||||
@@ -103,6 +105,17 @@ namespace Kernel::Input
|
||||
return;
|
||||
}
|
||||
|
||||
// If we could not detect scancode set, we assume it to be 1
|
||||
// If we get byte 0xF0 which is indicates release in scancode set 2
|
||||
// and nothing in scancode set 1, switch to scancode set 2
|
||||
if (m_scancode_set_uncertain && byte == 0xF0)
|
||||
{
|
||||
dprintln("Switching to scancode set 2");
|
||||
m_scancode_set_uncertain = false;
|
||||
m_scancode_set = 2;
|
||||
m_keymap.initialize(m_scancode_set);
|
||||
}
|
||||
|
||||
m_byte_buffer[m_byte_index++] = byte;
|
||||
if (byte == 0xE0)
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
bool Mutex::try_lock()
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
pid_t expected = -1;
|
||||
if (!m_locker.compare_exchange(expected, tid))
|
||||
return false;
|
||||
ASSERT(m_lock_depth == 0);
|
||||
if (tid)
|
||||
Thread::current().add_mutex();
|
||||
}
|
||||
m_lock_depth++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::lock()
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||
pid_t expected = -1;
|
||||
while (!m_locker.compare_exchange(expected, tid))
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||
Processor::yield();
|
||||
expected = -1;
|
||||
}
|
||||
ASSERT(m_lock_depth == 0);
|
||||
if (tid)
|
||||
Thread::current().add_mutex();
|
||||
}
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
||||
void Mutex::unlock()
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(m_locker == tid);
|
||||
ASSERT(m_lock_depth > 0);
|
||||
if (--m_lock_depth == 0)
|
||||
{
|
||||
m_locker = -1;
|
||||
if (tid)
|
||||
Thread::current().remove_mutex();
|
||||
}
|
||||
}
|
||||
|
||||
bool Mutex::is_locked_by_current_thread() const
|
||||
{
|
||||
return m_locker == Thread::current_tid();
|
||||
}
|
||||
|
||||
bool PriorityMutex::try_lock()
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||
pid_t expected = -1;
|
||||
if (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
|
||||
return false;
|
||||
if (has_priority)
|
||||
m_queue_length++;
|
||||
ASSERT(m_lock_depth == 0);
|
||||
if (tid)
|
||||
Thread::current().add_mutex();
|
||||
}
|
||||
m_lock_depth++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PriorityMutex::lock()
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
|
||||
if (tid == m_locker)
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
ASSERT(!tid || !Thread::current().has_spinlock());
|
||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||
if (has_priority)
|
||||
m_queue_length++;
|
||||
pid_t expected = -1;
|
||||
while (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||
Processor::yield();
|
||||
expected = -1;
|
||||
}
|
||||
ASSERT(m_lock_depth == 0);
|
||||
if (tid)
|
||||
Thread::current().add_mutex();
|
||||
}
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
||||
void PriorityMutex::unlock()
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(m_locker == tid);
|
||||
ASSERT(m_lock_depth > 0);
|
||||
if (--m_lock_depth == 0)
|
||||
{
|
||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||
if (has_priority)
|
||||
m_queue_length--;
|
||||
m_locker = -1;
|
||||
if (tid)
|
||||
Thread::current().remove_mutex();
|
||||
}
|
||||
}
|
||||
|
||||
bool PriorityMutex::is_locked_by_current_thread() const
|
||||
{
|
||||
return m_locker == Thread::current_tid();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
#include <kernel/Lock/BlockableSpinLock.h>
|
||||
#include <kernel/Lock/RWLock.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
void RWLock::rd_lock()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
while (m_writers_waiting > 0 || m_writer != -1)
|
||||
{
|
||||
BlockableSpinLock block(m_lock);
|
||||
m_thread_blocker.block_indefinite(&block);
|
||||
}
|
||||
m_readers_active++;
|
||||
}
|
||||
|
||||
void RWLock::rd_unlock()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
if (--m_readers_active == 0)
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
|
||||
void RWLock::wr_lock()
|
||||
{
|
||||
if (m_writer == Thread::current_tid())
|
||||
{
|
||||
m_writer_depth++;
|
||||
return;
|
||||
}
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
m_writers_waiting++;
|
||||
while (m_readers_active > 0 || m_writer != -1)
|
||||
{
|
||||
BlockableSpinLock block(m_lock);
|
||||
m_thread_blocker.block_indefinite(&block);
|
||||
}
|
||||
m_writers_waiting--;
|
||||
|
||||
m_writer = Thread::current_tid();
|
||||
m_writer_depth = 1;
|
||||
}
|
||||
|
||||
void RWLock::wr_unlock()
|
||||
{
|
||||
if (--m_writer_depth != 0)
|
||||
return;
|
||||
SpinLockGuard _(m_lock);
|
||||
m_writer = -1;
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -115,7 +115,7 @@ namespace Kernel
|
||||
return {};
|
||||
|
||||
const vaddr_t first_page = BAN::Math::max(m_vaddr, address) & PAGE_ADDR_MASK;
|
||||
const vaddr_t last_page = BAN::Math::div_round_up(BAN::Math::min(m_vaddr + m_size, address + size), PAGE_SIZE) * PAGE_SIZE;
|
||||
const vaddr_t last_page = BAN::Math::div_round_up<vaddr_t>(BAN::Math::min(m_vaddr + m_size, address + size), PAGE_SIZE) * PAGE_SIZE;
|
||||
|
||||
RWLockRDGuard _(m_shared_data->rw_lock);
|
||||
for (vaddr_t page_addr = first_page; page_addr < last_page; page_addr += PAGE_SIZE)
|
||||
|
||||
@@ -43,11 +43,10 @@ namespace Kernel
|
||||
PageTable::with_per_cpu_fast_page(current_paddr, [&page_matched_bit](void* addr) {
|
||||
for (size_t j = 0; j < PAGE_SIZE / sizeof(size_t); j++)
|
||||
{
|
||||
static_assert(sizeof(size_t) == sizeof(long));
|
||||
auto& current = static_cast<size_t*>(addr)[j];
|
||||
if (current == BAN::numeric_limits<size_t>::max())
|
||||
continue;
|
||||
const int ctz = __builtin_ctzl(~current);
|
||||
const int ctz = BAN::Math::ctz(~current);
|
||||
current |= static_cast<size_t>(1) << ctz;
|
||||
page_matched_bit = j * sizeof(size_t) * 8 + ctz;
|
||||
return;
|
||||
|
||||
@@ -93,7 +93,15 @@ namespace Kernel
|
||||
const pid_t pid = process.pid();
|
||||
const mode_t mode = shmflg & 0777;
|
||||
|
||||
auto object = TRY(BAN::RefPtr<Object>::create(key, shmid_ds {
|
||||
const int shmid = ({
|
||||
int id;
|
||||
do {
|
||||
id = Random::get<unsigned>() & BAN::numeric_limits<int>::max();
|
||||
} while (m_ids.contains(shmid));
|
||||
id;
|
||||
});
|
||||
|
||||
auto object = TRY(BAN::RefPtr<Object>::create(key, shmid, shmid_ds {
|
||||
.shm_perm = {
|
||||
.uid = uid,
|
||||
.gid = gid,
|
||||
@@ -109,13 +117,7 @@ namespace Kernel
|
||||
.shm_dtime = 0,
|
||||
.shm_ctime = SystemTimer::get().real_time().tv_sec,
|
||||
}));
|
||||
TRY(object->paddrs.resize(BAN::Math::div_round_up(size, PAGE_SIZE), 0));
|
||||
|
||||
auto generate_id = []() { return Random::get<unsigned>() & BAN::numeric_limits<int>::max(); };
|
||||
|
||||
int shmid = generate_id();
|
||||
while (m_ids.contains(shmid))
|
||||
shmid = generate_id();
|
||||
TRY(object->paddrs.resize(BAN::Math::div_round_up<size_t>(size, PAGE_SIZE), 0));
|
||||
|
||||
if (key != IPC_PRIVATE)
|
||||
TRY(m_ids.insert(key, shmid));
|
||||
@@ -222,14 +224,16 @@ namespace Kernel
|
||||
LockGuard _(m_object->mutex);
|
||||
m_object->info.shm_nattch++;
|
||||
m_object->info.shm_atime = SystemTimer::get().real_time().tv_sec;
|
||||
m_object->info.shm_lpid = Process::current().pid();
|
||||
}
|
||||
|
||||
SharedMemoryObject::~SharedMemoryObject()
|
||||
{
|
||||
LockGuard _(m_object->mutex);
|
||||
if (--m_object->info.shm_nattch == 0 && m_object->marked_for_deletion)
|
||||
SharedMemoryObjectManager::get().m_objects.remove(m_object->key);
|
||||
SharedMemoryObjectManager::get().m_objects.remove(m_object->id);
|
||||
m_object->info.shm_dtime = SystemTimer::get().real_time().tv_sec;
|
||||
m_object->info.shm_lpid = Process::current().pid();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> SharedMemoryObject::clone(PageTable& new_page_table)
|
||||
|
||||
@@ -125,8 +125,6 @@ struct BitmapAllocator
|
||||
// NOTE: We could optimize other bitmap functions than this
|
||||
// but this one is the bottle neck so it doesn't matter
|
||||
|
||||
static_assert(sizeof(unsigned long long) == sizeof(uint64_t));
|
||||
|
||||
if (index >= total_chunks)
|
||||
return index;
|
||||
|
||||
@@ -134,7 +132,7 @@ struct BitmapAllocator
|
||||
{
|
||||
const uint64_t qword = *reinterpret_cast<const uint64_t*>(base + (index - rem) / 8) >> rem;
|
||||
if (qword != (1ull << (64 - rem)) - 1)
|
||||
return index + __builtin_ctzll(~qword);
|
||||
return index + BAN::Math::ctz(~qword);
|
||||
index += 64 - rem;
|
||||
}
|
||||
|
||||
@@ -142,7 +140,7 @@ struct BitmapAllocator
|
||||
{
|
||||
const uint64_t qword = *reinterpret_cast<const uint64_t*>(base + index / 8);
|
||||
if (qword != UINT64_MAX)
|
||||
return index + __builtin_ctzll(~qword);
|
||||
return index + BAN::Math::ctz(~qword);
|
||||
index += 64;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <kernel/MMIO.h>
|
||||
#include <kernel/Networking/E1000/E1000.h>
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <kernel/Lock/BlockableSpinLock.h>
|
||||
#include <kernel/Networking/Loopback.h>
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
#include <kernel/Networking/RTL8169/Definitions.h>
|
||||
#include <kernel/Networking/RTL8169/RTL8169.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <kernel/Networking/TCPSocket.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Random.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace Kernel
|
||||
if (flags & ~(O_ACCMODE | O_NOFOLLOW | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT | O_NOCTTY | O_DIRECTORY | O_CREAT | O_EXCL | O_NONBLOCK))
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
|
||||
if ((flags & O_ACCMODE) != O_RDWR && __builtin_popcount(flags & O_ACCMODE) != 1)
|
||||
if ((flags & O_ACCMODE) != O_RDWR && BAN::Math::popcount<unsigned>(flags & O_ACCMODE) != 1)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
if ((flags & O_DIRECTORY) && !file.inode->mode().ifdir())
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptNumbers.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/PIC.h>
|
||||
|
||||
|
||||
+15
-10
@@ -696,19 +696,24 @@ namespace Kernel
|
||||
|
||||
size_t Process::proc_cputime(off_t offset, BAN::ByteSpan buffer) const
|
||||
{
|
||||
const uint64_t cpu_time_ns = [this] {
|
||||
uint64_t cpu_time_ns { 0 };
|
||||
uint64_t user_ns { 0 }, system_ns { 0 };
|
||||
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
for (auto* thread : m_threads)
|
||||
cpu_time_ns += thread->cpu_time_ns();
|
||||
return cpu_time_ns;
|
||||
}();
|
||||
{
|
||||
uint64_t u, s;
|
||||
thread->cpu_time_ns(u, s);
|
||||
user_ns += u;
|
||||
system_ns += s;
|
||||
}
|
||||
}
|
||||
|
||||
auto data = MUST(BAN::String::formatted("{}", cpu_time_ns));
|
||||
if (static_cast<size_t>(offset) >= data.size() + 1)
|
||||
auto data = MUST(BAN::String::formatted("{} {} {}", user_ns + system_ns, user_ns, system_ns));
|
||||
if (static_cast<size_t>(offset) >= data.size())
|
||||
return 0;
|
||||
|
||||
const size_t to_copy = BAN::Math::min<size_t>(data.size() - offset + 1, buffer.size());
|
||||
const size_t to_copy = BAN::Math::min<size_t>(data.size() - offset, buffer.size());
|
||||
memcpy(buffer.data(), data.data(), to_copy);
|
||||
return to_copy;
|
||||
}
|
||||
@@ -3054,7 +3059,7 @@ namespace Kernel
|
||||
LockGuard _(m_process_lock);
|
||||
uint64_t cpu_time_ns { 0 };
|
||||
for (auto* thread : m_threads)
|
||||
cpu_time_ns += thread->cpu_time_ns();
|
||||
cpu_time_ns += thread->cpu_time_total_ns();
|
||||
tp = {
|
||||
.tv_sec = static_cast<time_t>(cpu_time_ns / 1'000'000'000),
|
||||
.tv_nsec = static_cast<long>(cpu_time_ns % 1'000'000'000),
|
||||
@@ -3063,7 +3068,7 @@ namespace Kernel
|
||||
}
|
||||
case CLOCK_THREAD_CPUTIME_ID:
|
||||
{
|
||||
const auto cpu_time_ns = Thread::current().cpu_time_ns();
|
||||
const auto cpu_time_ns = Thread::current().cpu_time_total_ns();
|
||||
tp = {
|
||||
.tv_sec = static_cast<time_t>(cpu_time_ns / 1'000'000'000),
|
||||
.tv_nsec = static_cast<long>(cpu_time_ns % 1'000'000'000),
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#include <kernel/CPUID.h>
|
||||
#include <kernel/GDT.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Memory/Heap.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#include <kernel/Processor.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Terminal/TerminalDriver.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
+58
-126
@@ -1,11 +1,11 @@
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/Sort.h>
|
||||
#include <kernel/APIC.h>
|
||||
#include <kernel/GDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/SchedulerQueueNode.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
@@ -36,85 +36,6 @@ namespace Kernel
|
||||
|
||||
static BAN::Atomic<size_t> s_next_processor_index { 0 };
|
||||
|
||||
|
||||
void SchedulerQueue::add_thread_to_back(Node* node)
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
node->next = nullptr;
|
||||
node->prev = m_tail;
|
||||
(m_tail ? m_tail->next : m_head) = node;
|
||||
m_tail = node;
|
||||
}
|
||||
|
||||
bool SchedulerQueue::add_thread_with_wake_time(Node* node)
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
if (m_tail == nullptr || node->wake_time_ns >= m_tail->wake_time_ns)
|
||||
{
|
||||
add_thread_to_back(node);
|
||||
return node == m_head;
|
||||
}
|
||||
|
||||
Node* next = m_head;
|
||||
Node* prev = nullptr;
|
||||
while (next && node->wake_time_ns > next->wake_time_ns)
|
||||
{
|
||||
prev = next;
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
node->next = next;
|
||||
node->prev = prev;
|
||||
(next ? next->prev : m_tail) = node;
|
||||
(prev ? prev->next : m_head) = node;
|
||||
|
||||
return node == m_head;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
SchedulerQueue::Node* SchedulerQueue::remove_with_condition(F callback)
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
for (Node* node = m_head; node; node = node->next)
|
||||
{
|
||||
if (!callback(node))
|
||||
continue;
|
||||
remove_node(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SchedulerQueue::remove_node(Node* node)
|
||||
{
|
||||
(node->prev ? node->prev->next : m_head) = node->next;
|
||||
(node->next ? node->next->prev : m_tail) = node->prev;
|
||||
node->prev = nullptr;
|
||||
node->next = nullptr;
|
||||
}
|
||||
|
||||
SchedulerQueue::Node* SchedulerQueue::front()
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
ASSERT(!empty());
|
||||
return m_head;
|
||||
}
|
||||
|
||||
SchedulerQueue::Node* SchedulerQueue::pop_front()
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
if (empty())
|
||||
return nullptr;
|
||||
Node* result = m_head;
|
||||
m_head = m_head->next;
|
||||
(m_head ? m_head->prev : m_tail) = nullptr;
|
||||
result->next = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Scheduler*> Scheduler::create()
|
||||
{
|
||||
auto* scheduler = new Scheduler();
|
||||
@@ -142,7 +63,7 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
void Scheduler::add_current_to_most_loaded(SchedulerQueue* target_queue)
|
||||
void Scheduler::add_current_to_most_loaded(void* target_list)
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
@@ -151,7 +72,7 @@ namespace Kernel
|
||||
{
|
||||
if (info.node == m_current)
|
||||
{
|
||||
info.queue = target_queue;
|
||||
info.list = target_list;
|
||||
has_current = true;
|
||||
break;
|
||||
}
|
||||
@@ -163,8 +84,10 @@ namespace Kernel
|
||||
for (; index < m_most_loaded_threads.size() - 1; index++)
|
||||
if (m_most_loaded_threads[index].node == nullptr)
|
||||
break;
|
||||
m_most_loaded_threads[index].queue = target_queue;
|
||||
m_most_loaded_threads[index].node = m_current;
|
||||
m_most_loaded_threads[index] = {
|
||||
.list = target_list,
|
||||
.node = m_current,
|
||||
};
|
||||
}
|
||||
|
||||
BAN::sort::sort(m_most_loaded_threads.begin(), m_most_loaded_threads.end(),
|
||||
@@ -177,7 +100,7 @@ namespace Kernel
|
||||
);
|
||||
}
|
||||
|
||||
void Scheduler::update_most_loaded_node_queue(SchedulerQueue::Node* node, SchedulerQueue* target_queue)
|
||||
void Scheduler::update_most_loaded_node_list(SchedulerThreadNode* node, void* target_list)
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
@@ -185,13 +108,13 @@ namespace Kernel
|
||||
{
|
||||
if (info.node == node)
|
||||
{
|
||||
info.queue = target_queue;
|
||||
info.list = target_list;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::remove_node_from_most_loaded(SchedulerQueue::Node* node)
|
||||
void Scheduler::remove_node_from_most_loaded(SchedulerThreadNode* node)
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
@@ -203,8 +126,10 @@ namespace Kernel
|
||||
for (; i < m_most_loaded_threads.size() - 1; i++)
|
||||
m_most_loaded_threads[i] = m_most_loaded_threads[i + 1];
|
||||
|
||||
m_most_loaded_threads.back().node = nullptr;
|
||||
m_most_loaded_threads.back().queue = nullptr;
|
||||
m_most_loaded_threads.back() = {
|
||||
.list = nullptr,
|
||||
.node = nullptr,
|
||||
};
|
||||
}
|
||||
|
||||
void Scheduler::reschedule(YieldRegisters* yield_registers)
|
||||
@@ -212,7 +137,7 @@ namespace Kernel
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
// If there are no other threads in run queue, reschedule can be no-op :)
|
||||
if (m_run_queue.empty() && (!m_current || !m_current->blocked) && current_thread().state() == Thread::State::Executing)
|
||||
if (m_run_list.empty() && (!m_current || !m_current->blocked) && current_thread().state() == Thread::State::Executing)
|
||||
return;
|
||||
|
||||
if (m_current == nullptr)
|
||||
@@ -232,12 +157,13 @@ namespace Kernel
|
||||
case Thread::State::Executing:
|
||||
m_current->thread->yield_registers() = *yield_registers;
|
||||
m_current->time_used_ns += SystemTimer::get().ns_since_boot() - m_current->last_start_ns;
|
||||
add_current_to_most_loaded(m_current->blocked ? &m_block_queue : &m_run_queue);
|
||||
add_current_to_most_loaded(m_current->blocked ? static_cast<void*>(&m_block_list) : &m_run_list);
|
||||
if (!m_current->blocked)
|
||||
m_run_queue.add_thread_to_back(m_current);
|
||||
m_run_list.push(m_current);
|
||||
else
|
||||
{
|
||||
if (m_block_queue.add_thread_with_wake_time(m_current))
|
||||
m_block_list.push(m_current);
|
||||
if (m_block_list.front() == m_current)
|
||||
update_wake_up_deadline();
|
||||
Processor::set_disable_smp_messages(false);
|
||||
}
|
||||
@@ -246,12 +172,12 @@ namespace Kernel
|
||||
ASSERT(!m_current->blocked);
|
||||
m_current->time_used_ns = 0;
|
||||
remove_node_from_most_loaded(m_current);
|
||||
m_run_queue.add_thread_to_back(m_current);
|
||||
m_run_list.push(m_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ((m_current = m_run_queue.pop_front()))
|
||||
while ((m_current = m_run_list.pop_front()))
|
||||
{
|
||||
if (m_current->thread->state() != Thread::State::Terminated)
|
||||
break;
|
||||
@@ -273,7 +199,7 @@ namespace Kernel
|
||||
return;
|
||||
}
|
||||
|
||||
update_most_loaded_node_queue(m_current, nullptr);
|
||||
update_most_loaded_node_list(m_current, nullptr);
|
||||
|
||||
auto* thread = m_current->thread;
|
||||
|
||||
@@ -309,8 +235,8 @@ namespace Kernel
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
while (!m_block_queue.empty() && current_ns >= m_block_queue.front()->wake_time_ns)
|
||||
unblock_thread(m_block_queue.front());
|
||||
while (!m_block_list.empty() && current_ns >= m_block_list.front()->wake_time_ns)
|
||||
unblock_thread(m_block_list.front());
|
||||
}
|
||||
|
||||
void Scheduler::update_wake_up_deadline()
|
||||
@@ -324,8 +250,8 @@ namespace Kernel
|
||||
return;
|
||||
|
||||
uint64_t deadline_ns = m_next_reschedule_ns;
|
||||
if (!m_block_queue.empty())
|
||||
deadline_ns = BAN::Math::min(deadline_ns, m_block_queue.front()->wake_time_ns);
|
||||
if (!m_block_list.empty())
|
||||
deadline_ns = BAN::Math::min(deadline_ns, m_block_list.front()->wake_time_ns);
|
||||
if (Processor::is_smp_enabled())
|
||||
deadline_ns = BAN::Math::min(deadline_ns, m_last_load_balance_ns + s_load_balance_interval_ns);
|
||||
|
||||
@@ -336,7 +262,7 @@ namespace Kernel
|
||||
{
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
if ((is_idle() && !m_run_queue.empty()) || m_has_pending_reschedule)
|
||||
if ((is_idle() && !m_run_list.empty()) || m_has_pending_reschedule)
|
||||
{
|
||||
m_has_pending_reschedule = false;
|
||||
Processor::yield();
|
||||
@@ -374,7 +300,7 @@ namespace Kernel
|
||||
update_wake_up_deadline();
|
||||
}
|
||||
|
||||
void Scheduler::unblock_thread(SchedulerQueue::Node* node)
|
||||
void Scheduler::unblock_thread(SchedulerThreadNode* node)
|
||||
{
|
||||
auto state = Processor::get_interrupt_state();
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
@@ -385,12 +311,12 @@ namespace Kernel
|
||||
return;
|
||||
ASSERT(node != m_current);
|
||||
Processor::set_disable_smp_messages(true);
|
||||
m_block_queue.remove_node(node);
|
||||
m_block_list.pop(node);
|
||||
if (auto* blocker = node->blocker.load())
|
||||
blocker->remove_thread_from_block_queue(node);
|
||||
node->blocked = false;
|
||||
m_run_queue.add_thread_to_back(node);
|
||||
update_most_loaded_node_queue(node, &m_run_queue);
|
||||
m_run_list.push(node);
|
||||
update_most_loaded_node_list(node, &m_run_list);
|
||||
Processor::set_disable_smp_messages(false);
|
||||
}
|
||||
else
|
||||
@@ -404,7 +330,7 @@ namespace Kernel
|
||||
Processor::set_interrupt_state(state);
|
||||
}
|
||||
|
||||
void Scheduler::add_thread(SchedulerQueue::Node* node)
|
||||
void Scheduler::add_thread(SchedulerThreadNode* node)
|
||||
{
|
||||
auto state = Processor::get_interrupt_state();
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
@@ -412,9 +338,13 @@ namespace Kernel
|
||||
ASSERT(node->processor_id == Processor::current_id());
|
||||
|
||||
if (!node->blocked)
|
||||
m_run_queue.add_thread_to_back(node);
|
||||
else if (m_block_queue.add_thread_with_wake_time(node))
|
||||
m_run_list.push(node);
|
||||
else
|
||||
{
|
||||
m_block_list.push(node);
|
||||
if (m_block_list.front() == node)
|
||||
update_wake_up_deadline();
|
||||
}
|
||||
|
||||
if (auto* thread = node->thread; thread->is_userspace() && thread->has_process())
|
||||
thread->update_processor_index_address();
|
||||
@@ -482,21 +412,21 @@ namespace Kernel
|
||||
const uint64_t load_percent_x1000 = BAN::Math::div_round_up<uint64_t>(m_current->time_used_ns * 100'000, processing_ns);
|
||||
dprintln(" tid { 2}: { 3}.{3}% <{}> current", m_current->thread->tid(), load_percent_x1000 / 1000, load_percent_x1000 % 1000, name);
|
||||
}
|
||||
m_run_queue.remove_with_condition(
|
||||
[&](SchedulerQueue::Node* node)
|
||||
m_run_list.walk(
|
||||
[](const SchedulerThreadNode* node, void* arg)
|
||||
{
|
||||
const uint64_t processing_ns = *static_cast<const uint64_t*>(arg);
|
||||
const uint64_t load_percent_x1000 = BAN::Math::div_round_up<uint64_t>(node->time_used_ns * 100'000, processing_ns);
|
||||
dprintln(" tid { 2}: { 3}.{3}% active", node->thread->tid(), load_percent_x1000 / 1000, load_percent_x1000 % 1000);
|
||||
return false;
|
||||
}
|
||||
}, const_cast<uint64_t*>(&processing_ns)
|
||||
);
|
||||
m_block_queue.remove_with_condition(
|
||||
[&](SchedulerQueue::Node* node)
|
||||
m_block_list.walk(
|
||||
[](const SchedulerThreadNode* node, void* arg)
|
||||
{
|
||||
const uint64_t processing_ns = *static_cast<const uint64_t*>(arg);
|
||||
const uint64_t load_percent_x1000 = BAN::Math::div_round_up<uint64_t>(node->time_used_ns * 100'000, processing_ns);
|
||||
dprintln(" tid { 2}: { 3}.{3}% blocked", node->thread->tid(), load_percent_x1000 / 1000, load_percent_x1000 % 1000);
|
||||
return false;
|
||||
}
|
||||
}, const_cast<uint64_t*>(&processing_ns)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -532,7 +462,7 @@ namespace Kernel
|
||||
auto& thread_info = m_most_loaded_threads[i];
|
||||
if (thread_info.node == nullptr)
|
||||
break;
|
||||
if (thread_info.node == m_current || thread_info.queue == nullptr)
|
||||
if (thread_info.node == m_current || thread_info.list == nullptr)
|
||||
continue;
|
||||
|
||||
auto least_loaded_id = find_least_loaded_processor();
|
||||
@@ -596,11 +526,11 @@ namespace Kernel
|
||||
|
||||
thread_info.node->time_used_ns = 0;
|
||||
|
||||
{
|
||||
auto& my_queue = (thread_info.queue == &m_run_queue) ? m_run_queue : m_block_queue;
|
||||
my_queue.remove_node(thread_info.node);
|
||||
if (thread_info.list == &m_run_list)
|
||||
m_run_list.pop(thread_info.node);
|
||||
else
|
||||
m_block_list.pop(thread_info.node);
|
||||
m_thread_count--;
|
||||
}
|
||||
|
||||
thread_info.node->processor_id = least_loaded_id;
|
||||
Processor::send_smp_message(least_loaded_id, {
|
||||
@@ -608,8 +538,10 @@ namespace Kernel
|
||||
.new_thread = thread_info.node
|
||||
});
|
||||
|
||||
thread_info.node = nullptr;
|
||||
thread_info.queue = nullptr;
|
||||
thread_info = {
|
||||
.list = nullptr,
|
||||
.node = nullptr,
|
||||
};
|
||||
|
||||
if (m_idle_ns == 0)
|
||||
break;
|
||||
@@ -622,8 +554,8 @@ namespace Kernel
|
||||
m_current->time_used_ns = 0;
|
||||
for (auto& thread_info : m_most_loaded_threads)
|
||||
thread_info = {};
|
||||
m_run_queue .remove_with_condition([&](SchedulerQueue::Node* node) { node->time_used_ns = 0; return false; });
|
||||
m_block_queue.remove_with_condition([&](SchedulerQueue::Node* node) { node->time_used_ns = 0; return false; });
|
||||
m_run_list .walk([](const SchedulerThreadNode* node, void*) { const_cast<SchedulerThreadNode*>(node)->time_used_ns = 0; }, nullptr);
|
||||
m_block_list.walk([](const SchedulerThreadNode* node, void*) { const_cast<SchedulerThreadNode*>(node)->time_used_ns = 0; }, nullptr);
|
||||
m_idle_ns = 0;
|
||||
|
||||
m_should_calculate_max_load_threads = true;
|
||||
@@ -634,7 +566,7 @@ namespace Kernel
|
||||
BAN::ErrorOr<void> Scheduler::bind_thread_to_processor(Thread* thread, ProcessorID processor_id)
|
||||
{
|
||||
ASSERT(thread->m_scheduler_node == nullptr);
|
||||
auto* new_node = new SchedulerQueue::Node(thread);
|
||||
auto* new_node = new SchedulerThreadNode(thread);
|
||||
if (new_node == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Swap.h>
|
||||
#include <kernel/SchedulerThreadNode.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
SchedulerThreadNode* SchedulerQueue::front()
|
||||
{
|
||||
return m_head;
|
||||
}
|
||||
|
||||
SchedulerThreadNode* SchedulerQueue::pop_front()
|
||||
{
|
||||
if (empty())
|
||||
return nullptr;
|
||||
auto* const result = m_head;
|
||||
m_head = m_head->queue.next;
|
||||
(m_head ? m_head->queue.prev : m_tail) = nullptr;
|
||||
result->queue.prev = nullptr;
|
||||
result->queue.next = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
void SchedulerQueue::push(SchedulerThreadNode* node)
|
||||
{
|
||||
ASSERT(node->queue.prev == nullptr);
|
||||
ASSERT(node->queue.next == nullptr);
|
||||
|
||||
node->queue.prev = m_tail;
|
||||
node->queue.next = nullptr;
|
||||
(m_tail ? m_tail->queue.next : m_head) = node;
|
||||
m_tail = node;
|
||||
}
|
||||
|
||||
void SchedulerQueue::pop(SchedulerThreadNode* node)
|
||||
{
|
||||
(node->queue.prev ? node->queue.prev->queue.next : m_head) = node->queue.next;
|
||||
(node->queue.next ? node->queue.next->queue.prev : m_tail) = node->queue.prev;
|
||||
node->queue.prev = nullptr;
|
||||
node->queue.next = nullptr;
|
||||
}
|
||||
|
||||
void SchedulerQueue::walk(void (*callback)(const SchedulerThreadNode*, void*), void* arg) const
|
||||
{
|
||||
for (auto* node = m_head; node; node = node->queue.next)
|
||||
callback(node, arg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
SchedulerThreadNode* SchedulerHeap::front()
|
||||
{
|
||||
return m_root;
|
||||
}
|
||||
|
||||
SchedulerThreadNode* SchedulerHeap::pop_front()
|
||||
{
|
||||
if (empty())
|
||||
return nullptr;
|
||||
auto* const result = m_root;
|
||||
pop(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void SchedulerHeap::push(SchedulerThreadNode* node)
|
||||
{
|
||||
ASSERT(node->heap.parent == nullptr);
|
||||
ASSERT(node->heap.lchild == nullptr);
|
||||
ASSERT(node->heap.rchild == nullptr);
|
||||
|
||||
if (m_root == nullptr)
|
||||
{
|
||||
// push to empty heap
|
||||
node->heap.parent = nullptr;
|
||||
node->heap.lchild = nullptr;
|
||||
node->heap.rchild = nullptr;
|
||||
m_root = node;
|
||||
m_last = node;
|
||||
return;
|
||||
}
|
||||
|
||||
auto* parent = m_last;
|
||||
|
||||
{
|
||||
// find parent of the new node
|
||||
SchedulerThreadNode* temp;
|
||||
while ((temp = parent->heap.parent) && parent == temp->heap.rchild)
|
||||
parent = temp;
|
||||
if (temp && temp->heap.rchild == nullptr)
|
||||
parent = temp;
|
||||
else
|
||||
{
|
||||
if (temp != nullptr)
|
||||
parent = temp->heap.rchild;
|
||||
while ((temp = parent->heap.lchild))
|
||||
parent = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// insert node as the last node
|
||||
(parent->heap.lchild ? parent->heap.rchild : parent->heap.lchild) = node;
|
||||
node->heap.parent = parent;
|
||||
node->heap.lchild = nullptr;
|
||||
node->heap.rchild = nullptr;
|
||||
m_last = node;
|
||||
|
||||
// fix heap properties
|
||||
while ((parent = node->heap.parent) && node->wake_time_ns < parent->wake_time_ns)
|
||||
swap_nodes(node, parent);
|
||||
}
|
||||
|
||||
void SchedulerHeap::pop(SchedulerThreadNode* old_node)
|
||||
{
|
||||
if (m_root == m_last)
|
||||
{
|
||||
// remove the only node
|
||||
old_node->heap.parent = nullptr;
|
||||
old_node->heap.lchild = nullptr;
|
||||
old_node->heap.rchild = nullptr;
|
||||
m_root = nullptr;
|
||||
m_last = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
auto* fix_node = m_last;
|
||||
swap_nodes(old_node, m_last);
|
||||
|
||||
{
|
||||
// update last to point to the previous node
|
||||
SchedulerThreadNode* temp;
|
||||
while ((temp = m_last->heap.parent) && m_last == temp->heap.lchild)
|
||||
m_last = temp;
|
||||
if (temp != nullptr)
|
||||
m_last = temp->heap.lchild;
|
||||
ASSERT(m_last);
|
||||
while ((temp = m_last->heap.rchild))
|
||||
m_last = temp;
|
||||
}
|
||||
|
||||
{
|
||||
// delete links to/from the deleted node
|
||||
if (auto* parent = old_node->heap.parent)
|
||||
(old_node == parent->heap.rchild ? parent->heap.rchild : parent->heap.lchild) = nullptr;
|
||||
old_node->heap.parent = nullptr;
|
||||
old_node->heap.lchild = nullptr;
|
||||
old_node->heap.rchild = nullptr;
|
||||
}
|
||||
|
||||
// fix heap properties
|
||||
if (fix_node->wake_time_ns == old_node->wake_time_ns)
|
||||
;
|
||||
else if (fix_node->wake_time_ns < old_node->wake_time_ns)
|
||||
{
|
||||
SchedulerThreadNode* parent;
|
||||
while ((parent = fix_node->heap.parent) && fix_node->wake_time_ns < parent->wake_time_ns)
|
||||
swap_nodes(fix_node, parent);
|
||||
}
|
||||
else for (;;)
|
||||
{
|
||||
const bool l_ok = !fix_node->heap.lchild || fix_node->wake_time_ns <= fix_node->heap.lchild->wake_time_ns;
|
||||
const bool r_ok = !fix_node->heap.rchild || fix_node->wake_time_ns <= fix_node->heap.rchild->wake_time_ns;
|
||||
if (l_ok && r_ok)
|
||||
break;
|
||||
auto* child = (!l_ok && !r_ok)
|
||||
? (fix_node->heap.lchild->wake_time_ns < fix_node->heap.rchild->wake_time_ns ? fix_node->heap.lchild : fix_node->heap.rchild)
|
||||
: (r_ok ? fix_node->heap.lchild : fix_node->heap.rchild);
|
||||
swap_nodes(fix_node, child);
|
||||
}
|
||||
}
|
||||
|
||||
void SchedulerHeap::walk(void (*callback)(const SchedulerThreadNode*, void*), void* arg) const
|
||||
{
|
||||
walk_impl(callback, arg, m_root);
|
||||
}
|
||||
|
||||
void SchedulerHeap::walk_impl(void (*callback)(const SchedulerThreadNode*, void*), void* arg, const SchedulerThreadNode* node) const
|
||||
{
|
||||
if (node == nullptr)
|
||||
return;
|
||||
callback(node, arg);
|
||||
walk_impl(callback, arg, node->heap.lchild);
|
||||
walk_impl(callback, arg, node->heap.rchild);
|
||||
}
|
||||
|
||||
void SchedulerHeap::swap_nodes(SchedulerThreadNode* node1, SchedulerThreadNode* node2)
|
||||
{
|
||||
if (node1 == node2)
|
||||
return;
|
||||
|
||||
if (node2 == node1->heap.parent)
|
||||
BAN::swap(node1, node2);
|
||||
|
||||
auto* const p1 = node1->heap.parent;
|
||||
auto* const l1 = node1->heap.lchild;
|
||||
auto* const r1 = node1->heap.rchild;
|
||||
|
||||
auto* const p2 = node2->heap.parent;
|
||||
auto* const l2 = node2->heap.lchild;
|
||||
auto* const r2 = node2->heap.rchild;
|
||||
|
||||
if (node1 == node2->heap.parent)
|
||||
{
|
||||
node1->heap.parent = node2;
|
||||
node1->heap.lchild = l2;
|
||||
node1->heap.rchild = r2;
|
||||
|
||||
node2->heap.parent = p1;
|
||||
|
||||
if (l1 == node2)
|
||||
{
|
||||
node2->heap.lchild = node1;
|
||||
node2->heap.rchild = r1;
|
||||
if (r1) r1->heap.parent = node2;
|
||||
}
|
||||
else
|
||||
{
|
||||
node2->heap.lchild = l1;
|
||||
node2->heap.rchild = node1;
|
||||
if (l1) l1->heap.parent = node2;
|
||||
}
|
||||
|
||||
if (p1) (node1 == p1->heap.lchild ? p1->heap.lchild : p1->heap.rchild) = node2;
|
||||
|
||||
if (l2) l2->heap.parent = node1;
|
||||
if (r2) r2->heap.parent = node1;
|
||||
}
|
||||
else
|
||||
{
|
||||
node1->heap.parent = p2;
|
||||
node1->heap.lchild = l2;
|
||||
node1->heap.rchild = r2;
|
||||
|
||||
node2->heap.parent = p1;
|
||||
node2->heap.lchild = l1;
|
||||
node2->heap.rchild = r1;
|
||||
|
||||
if (l1) l1->heap.parent = node2;
|
||||
if (r1) r1->heap.parent = node2;
|
||||
|
||||
if (l2) l2->heap.parent = node1;
|
||||
if (r2) r2->heap.parent = node1;
|
||||
|
||||
if (p1 || p2)
|
||||
{
|
||||
if (p1 == p2)
|
||||
BAN::swap(p1->heap.lchild, p1->heap.rchild);
|
||||
else
|
||||
{
|
||||
if (p1) (p1->heap.lchild == node1 ? p1->heap.lchild : p1->heap.rchild) = node2;
|
||||
if (p2) (p2->heap.lchild == node2 ? p2->heap.lchild : p2->heap.rchild) = node1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto* const root = m_root;
|
||||
auto* const last = m_last;
|
||||
|
||||
if (node1 == root) m_root = node2;
|
||||
else if (node1 == last) m_last = node2;
|
||||
|
||||
if (node2 == root) m_root = node1;
|
||||
else if (node2 == last) m_last = node1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -94,7 +94,7 @@ namespace Kernel
|
||||
|
||||
while (is != 0)
|
||||
{
|
||||
const size_t idx = __builtin_ctz(is);
|
||||
const size_t idx = BAN::Math::ctz(is);
|
||||
if (auto& device = m_devices[idx])
|
||||
device->handle_irq();
|
||||
else
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <kernel/Lock/BlockableSpinLock.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
||||
@@ -301,7 +302,7 @@ namespace Kernel
|
||||
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);
|
||||
const size_t bytes = BAN::Math::min<size_t>(buffer.size(), PAGE_SIZE - buffer_vaddr % PAGE_SIZE);
|
||||
|
||||
bool can_extend = true;
|
||||
if (prdt_count == 0)
|
||||
@@ -424,7 +425,7 @@ namespace Kernel
|
||||
{
|
||||
if (const uint32_t usable_slots = ~(m_port->sact | m_port->ci) & m_free_slots)
|
||||
{
|
||||
const uint32_t slot = __builtin_ctz(usable_slots);
|
||||
const uint32_t slot = BAN::Math::ctz(usable_slots);
|
||||
m_free_slots &= ~(1u << slot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ namespace Kernel
|
||||
|
||||
extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)
|
||||
{
|
||||
Thread::current().set_is_in_syscall(true);
|
||||
|
||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||
|
||||
Process::current().wait_while_stopped();
|
||||
@@ -101,6 +103,8 @@ namespace Kernel
|
||||
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
Thread::current().set_is_in_syscall(false);
|
||||
|
||||
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
|
||||
|
||||
if (ret.is_error())
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Lock/BlockableSpinLock.h>
|
||||
#include <kernel/Terminal/PseudoTerminal.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
#include <BAN/ScopeGuard.h>
|
||||
|
||||
|
||||
@@ -237,8 +237,6 @@ namespace Kernel
|
||||
if (ch == _POSIX_VDISABLE)
|
||||
return;
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
const auto termios = get_termios();
|
||||
|
||||
if ((termios.c_iflag & ISTRIP))
|
||||
@@ -271,6 +269,8 @@ namespace Kernel
|
||||
bool should_flush = false;
|
||||
bool force_echo = false;
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
if (!(termios.c_lflag & ICANON))
|
||||
should_flush = true;
|
||||
else
|
||||
|
||||
@@ -47,9 +47,8 @@ namespace Kernel
|
||||
}, 0600, 0, 0)
|
||||
, m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++)))
|
||||
, m_terminal_driver(driver)
|
||||
, m_palette(driver->palette())
|
||||
, m_foreground(m_palette[15])
|
||||
, m_background(m_palette[0])
|
||||
, m_foreground(driver->palette()[15])
|
||||
, m_background(driver->palette()[0])
|
||||
{
|
||||
m_width = m_terminal_driver->width();
|
||||
m_height = m_terminal_driver->height();
|
||||
@@ -122,11 +121,14 @@ namespace Kernel
|
||||
void VirtualTTY::handle_ansi_csi_color(uint8_t value)
|
||||
{
|
||||
ASSERT(m_write_lock.is_locked_by_current_thread());
|
||||
|
||||
auto& palette = m_terminal_driver->palette();
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
m_foreground = m_palette[15];
|
||||
m_background = m_palette[0];
|
||||
m_foreground = palette[15];
|
||||
m_background = palette[0];
|
||||
m_colors_inverted = false;
|
||||
break;
|
||||
|
||||
@@ -138,25 +140,25 @@ namespace Kernel
|
||||
case 27: m_colors_inverted = false; break;
|
||||
|
||||
case 30 ... 37:
|
||||
m_foreground = m_palette[value - 30];
|
||||
m_foreground = palette[value - 30];
|
||||
break;
|
||||
case 39:
|
||||
m_foreground = m_palette[15];
|
||||
m_foreground = palette[15];
|
||||
break;
|
||||
|
||||
case 40 ... 47:
|
||||
m_background = m_palette[value - 40];
|
||||
m_background = palette[value - 40];
|
||||
break;
|
||||
case 49:
|
||||
m_background = m_palette[0];
|
||||
m_background = palette[0];
|
||||
break;
|
||||
|
||||
case 90 ... 97:
|
||||
m_foreground = m_palette[value - 90 + 8];
|
||||
m_foreground = palette[value - 90 + 8];
|
||||
break;
|
||||
|
||||
case 100 ... 107:
|
||||
m_background = m_palette[value - 100 + 8];
|
||||
m_background = palette[value - 100 + 8];
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -173,7 +175,7 @@ namespace Kernel
|
||||
|
||||
const uint8_t code = BAN::Math::min(m_ansi_state.nums[2], 255);
|
||||
if (code < 16)
|
||||
return m_palette[code];
|
||||
return m_terminal_driver->palette()[code];
|
||||
|
||||
if (code < 232)
|
||||
{
|
||||
|
||||
@@ -285,12 +285,22 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t Thread::cpu_time_ns() const
|
||||
uint64_t Thread::cpu_time_total_ns() const
|
||||
{
|
||||
SpinLockGuard _(m_cpu_time_lock);
|
||||
if (m_cpu_time_start_ns == UINT64_MAX)
|
||||
return m_cpu_time_ns;
|
||||
return m_cpu_time_ns + (SystemTimer::get().ns_since_boot() - m_cpu_time_start_ns);
|
||||
uint64_t offset = 0;
|
||||
if (m_cpu_time_start_ns != UINT64_MAX)
|
||||
offset += SystemTimer::get().ns_since_boot() - m_cpu_time_start_ns;
|
||||
return m_cpu_time_user_ns + m_cpu_time_system_ns + offset;
|
||||
}
|
||||
|
||||
void Thread::cpu_time_ns(uint64_t& user_ns, uint64_t& system_ns) const
|
||||
{
|
||||
SpinLockGuard _(m_cpu_time_lock);
|
||||
user_ns = m_cpu_time_user_ns;
|
||||
system_ns = m_cpu_time_system_ns;
|
||||
if (m_cpu_time_start_ns != UINT64_MAX)
|
||||
system_ns += SystemTimer::get().ns_since_boot() - m_cpu_time_start_ns;
|
||||
}
|
||||
|
||||
void Thread::set_cpu_time_start()
|
||||
@@ -304,10 +314,21 @@ namespace Kernel
|
||||
{
|
||||
SpinLockGuard _(m_cpu_time_lock);
|
||||
ASSERT(m_cpu_time_start_ns != UINT64_MAX);
|
||||
m_cpu_time_ns += SystemTimer::get().ns_since_boot() - m_cpu_time_start_ns;
|
||||
uint64_t& value = m_is_in_syscall ? m_cpu_time_system_ns : m_cpu_time_user_ns;
|
||||
value += SystemTimer::get().ns_since_boot() - m_cpu_time_start_ns;
|
||||
m_cpu_time_start_ns = UINT64_MAX;
|
||||
}
|
||||
|
||||
void Thread::set_is_in_syscall(bool is_in_syscall)
|
||||
{
|
||||
SpinLockGuard _(m_cpu_time_lock);
|
||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
uint64_t& value = m_is_in_syscall ? m_cpu_time_system_ns : m_cpu_time_user_ns;
|
||||
value += current_ns - m_cpu_time_start_ns;
|
||||
m_is_in_syscall = is_in_syscall;
|
||||
m_cpu_time_start_ns = current_ns;
|
||||
}
|
||||
|
||||
void Thread::update_processor_index_address()
|
||||
{
|
||||
if (!is_userspace() || !has_process())
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <kernel/Processor.h>
|
||||
#include <kernel/SchedulerQueueNode.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/SchedulerThreadNode.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
@@ -44,7 +45,7 @@ namespace Kernel
|
||||
m_block_chain = nullptr;
|
||||
}
|
||||
|
||||
void ThreadBlocker::add_thread_to_block_queue(SchedulerQueue::Node* node)
|
||||
void ThreadBlocker::add_thread_to_block_queue(SchedulerThreadNode* node)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
@@ -60,7 +61,7 @@ namespace Kernel
|
||||
m_block_chain = node;
|
||||
}
|
||||
|
||||
void ThreadBlocker::remove_thread_from_block_queue(SchedulerQueue::Node* node)
|
||||
void ThreadBlocker::remove_thread_from_block_queue(SchedulerThreadNode* node)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/MMIO.h>
|
||||
#include <kernel/Processor.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Timer/HPET.h>
|
||||
|
||||
#define HPET_PERIOD_MAX 0x05F5E100
|
||||
@@ -135,8 +136,7 @@ namespace Kernel
|
||||
auto* header = static_cast<const ACPI::HPET*>(ACPI::ACPI::get().get_header("HPET"_sv, 0));
|
||||
if (header == nullptr)
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
|
||||
if (header->hardware_rev_id == 0)
|
||||
if (header->length < sizeof(ACPI::HPET))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
if (!InterruptController::get().is_using_apic() && !header->legacy_replacement_irq_routing_cable)
|
||||
@@ -152,6 +152,12 @@ namespace Kernel
|
||||
|
||||
auto& regs = registers();
|
||||
|
||||
if ((regs.capabilities & 0xFF) == 0)
|
||||
{
|
||||
dwarnln("HPET: Invalid revision");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
#if ARCH(x86_64)
|
||||
m_is_64bit = regs.capabilities & COUNT_SIZE_CAP;
|
||||
#else
|
||||
@@ -191,17 +197,36 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
// set timer period to 1000 Hz
|
||||
const uint64_t ticks_per_ms = m_ticks_per_s / 1000;
|
||||
|
||||
#if ARCH(x86_64)
|
||||
const bool use_64bit_timer = !!(timer0.configuration & Tn_SIZE_CAP);
|
||||
#else
|
||||
// Spec recommends using 32 bit timers when the cpu can't do atomic 64 bit accesses
|
||||
const bool use_64bit_timer = !!(timer0.configuration & Tn_SIZE_CAP) && (ticks_per_ms > 0xFFFFFFFF);
|
||||
#endif
|
||||
|
||||
if (!use_64bit_timer && ticks_per_ms >= 0x100000000)
|
||||
{
|
||||
dprintln("HPET: cannot create 1 kHz timer");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
// enable interrupts
|
||||
timer0.configuration = timer0.configuration | Tn_INT_ENB_CNF;
|
||||
timer0.configuration |= Tn_INT_ENB_CNF;
|
||||
// edge triggered interrupts
|
||||
timer0.configuration = timer0.configuration & ~Tn_INT_TYPE_CNF;
|
||||
timer0.configuration &= ~Tn_INT_TYPE_CNF;
|
||||
// periodic timer
|
||||
timer0.configuration = timer0.configuration | Tn_TYPE_CNF;
|
||||
// disable 32 bit mode
|
||||
timer0.configuration = timer0.configuration & ~Tn_32MODE_CNF;
|
||||
timer0.configuration |= Tn_TYPE_CNF;
|
||||
// set 32 bit mode
|
||||
if (use_64bit_timer)
|
||||
timer0.configuration &= ~Tn_32MODE_CNF;
|
||||
else
|
||||
timer0.configuration |= Tn_32MODE_CNF;
|
||||
// disable FSB interrupts
|
||||
if (timer0.configuration & Tn_FSB_INT_DEL_CAP)
|
||||
timer0.configuration = timer0.configuration & ~Tn_FSB_EN_CNF;
|
||||
timer0.configuration &= ~Tn_FSB_EN_CNF;
|
||||
|
||||
uint16_t irq;
|
||||
if (header->legacy_replacement_irq_routing_cable)
|
||||
@@ -238,27 +263,29 @@ namespace Kernel
|
||||
timer0.configuration = (timer0.configuration & ~Tn_INT_ROUTE_CNF_MASK) | (gsi << Tn_INT_ROUTE_CNF_SHIFT);
|
||||
}
|
||||
|
||||
// set timer period to 1000 Hz
|
||||
const uint64_t ticks_per_ms = m_ticks_per_s / 1000;
|
||||
if (use_64bit_timer)
|
||||
{
|
||||
#if ARCH(x86_64)
|
||||
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
|
||||
timer0.comparator.full = ticks_per_ms;
|
||||
#else
|
||||
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
|
||||
timer0.comparator.low = ticks_per_ms;
|
||||
if (timer0.configuration & Tn_SIZE_CAP)
|
||||
{
|
||||
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
|
||||
timer0.comparator.high = ticks_per_ms >> 32;
|
||||
#endif
|
||||
}
|
||||
else if (ticks_per_ms > 0xFFFFFFFF)
|
||||
else
|
||||
{
|
||||
dprintln("HPET: cannot create 1 kHz timer");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
|
||||
timer0.comparator.low = ticks_per_ms;
|
||||
}
|
||||
|
||||
// enable main counter
|
||||
regs.configuration.low = regs.configuration.low | ENABLE_CNF;
|
||||
|
||||
set_irq(irq);
|
||||
InterruptController::get().enable_irq(irq);
|
||||
|
||||
regs.configuration.low = regs.configuration.low | ENABLE_CNF;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Processor.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Timer/PIT.h>
|
||||
|
||||
#define PIT_IRQ 0
|
||||
|
||||
@@ -252,14 +252,19 @@ namespace Kernel
|
||||
dwarnln("Could not initialize USB interface {}", ret.error());
|
||||
m_class_drivers.remove(i--);
|
||||
}
|
||||
else if (m_class_drivers[i]->is_hid_driver() && static_cast<USBHIDDriver*>(m_class_drivers[i].ptr())->has_led_control())
|
||||
TRY(m_hid_info.led_controls.push_back(m_class_drivers[i].ptr()));
|
||||
}
|
||||
|
||||
if (!m_class_drivers.empty())
|
||||
{
|
||||
update_led_mask(m_hid_info.led_mask);
|
||||
|
||||
dprintln("Successfully initialized USB device with {}/{} interfaces",
|
||||
m_class_drivers.size(),
|
||||
configuration.interfaces.size()
|
||||
);
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -363,4 +368,13 @@ namespace Kernel
|
||||
driver->handle_input_data(byte_count, endpoint_id);
|
||||
}
|
||||
|
||||
void USBDevice::update_led_mask(uint32_t led_mask)
|
||||
{
|
||||
const uint32_t old_mask = m_hid_info.led_mask.exchange(led_mask);
|
||||
if (old_mask == led_mask)
|
||||
return;
|
||||
for (auto* led_control : m_hid_info.led_controls)
|
||||
static_cast<USBHIDDriver*>(led_control)->set_leds(led_mask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Kernel
|
||||
|
||||
enum HIDRequest : uint8_t
|
||||
{
|
||||
GET_PROTOCOL = 0x03,
|
||||
SET_PROTOCOL = 0x0B,
|
||||
};
|
||||
|
||||
@@ -77,14 +78,14 @@ namespace Kernel
|
||||
|
||||
USBHIDDriver::~USBHIDDriver()
|
||||
{
|
||||
for (auto& device_input : m_device_inputs)
|
||||
if (device_input.device)
|
||||
DevFileSystem::get().remove_device(device_input.device);
|
||||
for (auto& device_report : m_device_reports)
|
||||
if (device_report.device)
|
||||
DevFileSystem::get().remove_device(device_report.device);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> USBHIDDriver::initialize()
|
||||
{
|
||||
auto dma_buffer = TRY(DMARegion::create(1024));
|
||||
auto dma_buffer = TRY(DMARegion::create(1024, PageTable::MemoryType::Normal));
|
||||
|
||||
ASSERT(static_cast<USB::InterfaceBaseClass>(m_interface.descriptor.bInterfaceClass) == USB::InterfaceBaseClass::HID);
|
||||
|
||||
@@ -119,13 +120,14 @@ namespace Kernel
|
||||
// If this device supports boot protocol, make sure it is not used
|
||||
if (m_interface.descriptor.bInterfaceSubClass == 0x01)
|
||||
{
|
||||
USBDeviceRequest request;
|
||||
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Interface;
|
||||
request.bRequest = HIDRequest::SET_PROTOCOL;
|
||||
request.wValue = 1; // report protocol
|
||||
request.wIndex = m_interface.descriptor.bInterfaceNumber;
|
||||
request.wLength = 0;
|
||||
TRY(m_device.send_request(request, 0));
|
||||
const auto request = USBDeviceRequest {
|
||||
.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Interface,
|
||||
.bRequest = HIDRequest::SET_PROTOCOL,
|
||||
.wValue = 1, // report protocol
|
||||
.wIndex = m_interface.descriptor.bInterfaceNumber,
|
||||
.wLength = 0,
|
||||
};
|
||||
(void)m_device.send_request(request, 0);
|
||||
}
|
||||
|
||||
const auto& hid_descriptor = *reinterpret_cast<const HIDDescriptor*>(m_interface.misc_descriptors[hid_descriptor_index].data());
|
||||
@@ -184,7 +186,10 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
m_device_inputs = TRY(initializes_device_reports(collections));
|
||||
TRY(initializes_device_reports(collections));
|
||||
|
||||
if (has_led_control())
|
||||
m_led_region = TRY(DMARegion::create(PAGE_SIZE, PageTable::MemoryType::Normal));
|
||||
|
||||
for (const auto& endpoint : m_interface.endpoints)
|
||||
{
|
||||
@@ -196,7 +201,7 @@ namespace Kernel
|
||||
continue;
|
||||
|
||||
TRY(m_device.configure_endpoint(desc));
|
||||
m_data_buffer = TRY(DMARegion::create(desc.wMaxPacketSize & 0x07FF));
|
||||
m_data_buffer = TRY(DMARegion::create(desc.wMaxPacketSize & 0x07FF, PageTable::MemoryType::Normal));
|
||||
|
||||
m_data_endpoint_id = (desc.bEndpointAddress & 0x0F) * 2 + !!(desc.bEndpointAddress & 0x80);
|
||||
|
||||
@@ -209,7 +214,7 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
for (auto& report : m_device_inputs)
|
||||
for (auto& report : m_device_reports)
|
||||
if (report.device && report.device->initialize().is_error())
|
||||
report.device.clear();
|
||||
|
||||
@@ -238,10 +243,9 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::Vector<USBHIDDriver::DeviceReport>> USBHIDDriver::initializes_device_reports(const BAN::Vector<USBHID::Collection>& collection_list)
|
||||
BAN::ErrorOr<void> USBHIDDriver::initializes_device_reports(const BAN::Vector<USBHID::Collection>& collection_list)
|
||||
{
|
||||
BAN::Vector<USBHIDDriver::DeviceReport> result;
|
||||
TRY(result.reserve(collection_list.size()));
|
||||
TRY(m_device_reports.reserve(collection_list.size()));
|
||||
|
||||
for (size_t i = 0; i < collection_list.size(); i++)
|
||||
{
|
||||
@@ -249,9 +253,7 @@ namespace Kernel
|
||||
|
||||
USBHIDDriver::DeviceReport report;
|
||||
TRY(gather_collection_reports(collection, report.inputs, USBHID::Report::Type::Input));
|
||||
|
||||
BAN::Vector<USBHID::Report> outputs;
|
||||
TRY(gather_collection_reports(collection, outputs, USBHID::Report::Type::Output));
|
||||
TRY(gather_collection_reports(collection, report.outputs, USBHID::Report::Type::Output));
|
||||
|
||||
switch (collection.usage_page)
|
||||
{
|
||||
@@ -267,7 +269,7 @@ namespace Kernel
|
||||
dprintln("Initialized an USB Joystick");
|
||||
break;
|
||||
case 0x06:
|
||||
report.device = TRY(BAN::RefPtr<USBKeyboard>::create(*this, BAN::move(outputs)));
|
||||
report.device = TRY(BAN::RefPtr<USBKeyboard>::create(*this));
|
||||
dprintln("Initialized an USB Keyboard");
|
||||
break;
|
||||
default:
|
||||
@@ -279,19 +281,47 @@ namespace Kernel
|
||||
switch (collection.usage_id)
|
||||
{
|
||||
case 0x01:
|
||||
report.device = TRY(BAN::RefPtr<USBKeyboard>::create(*this, BAN::move(outputs)));
|
||||
report.device = TRY(BAN::RefPtr<USBKeyboard>::create(*this));
|
||||
dprintln("Initialized an USB Consumer Control");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TRY(result.push_back(BAN::move(report)));
|
||||
TRY(m_device_reports.push_back(BAN::move(report)));
|
||||
}
|
||||
|
||||
for (auto& report : result)
|
||||
if (report.device)
|
||||
for (auto& report : m_device_reports)
|
||||
{
|
||||
if (!report.device)
|
||||
continue;
|
||||
DevFileSystem::get().add_device(report.device);
|
||||
return BAN::move(result);
|
||||
|
||||
uint8_t led_report_ids[0x100 / 8] {};
|
||||
for (const auto& output : report.outputs)
|
||||
{
|
||||
if (output.usage_page != 0x08)
|
||||
continue;
|
||||
|
||||
const auto byte = output.report_id / 8;
|
||||
const auto bit = output.report_id % 8;
|
||||
if (led_report_ids[byte] & (1u << bit))
|
||||
continue;
|
||||
led_report_ids[byte] |= (1u << bit);
|
||||
|
||||
uint32_t report_bits = 0;
|
||||
for (const auto& temp : report.outputs)
|
||||
if (temp.report_id == output.report_id)
|
||||
report_bits += temp.report_size * temp.report_count;
|
||||
|
||||
TRY(m_led_controls.push_back({
|
||||
.report = &m_device_reports.back(),
|
||||
.report_id = output.report_id,
|
||||
.report_bits = report_bits,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void USBHIDDriver::handle_stall(uint8_t endpoint_id)
|
||||
@@ -368,19 +398,19 @@ namespace Kernel
|
||||
}
|
||||
|
||||
size_t bit_offset = 0;
|
||||
for (auto& device_input : m_device_inputs)
|
||||
for (auto& device_report : m_device_reports)
|
||||
{
|
||||
if (device_input.device)
|
||||
device_input.device->start_report();
|
||||
if (device_report.device)
|
||||
device_report.device->start_report();
|
||||
|
||||
for (const auto& input : device_input.inputs)
|
||||
for (const auto& input : device_report.inputs)
|
||||
{
|
||||
if (report_id.value_or(input.report_id) != input.report_id)
|
||||
continue;
|
||||
|
||||
ASSERT(input.report_size <= 32);
|
||||
|
||||
if (!device_input.device || (input.usage_id == 0 && input.usage_minimum == 0 && input.usage_maximum == 0))
|
||||
if (!device_report.device || (input.usage_id == 0 && input.usage_minimum == 0 && input.usage_maximum == 0))
|
||||
{
|
||||
bit_offset += input.report_size * input.report_count;
|
||||
continue;
|
||||
@@ -401,7 +431,7 @@ namespace Kernel
|
||||
const auto usage = input.usage_id ? input.usage_id : (input.usage_minimum + (variable ? i : logical));
|
||||
|
||||
if (!variable)
|
||||
device_input.device->handle_array(input.usage_page, usage);
|
||||
device_report.device->handle_array(input.usage_page, usage);
|
||||
else
|
||||
{
|
||||
const int64_t physical =
|
||||
@@ -411,17 +441,51 @@ namespace Kernel
|
||||
input.physical_minimum;
|
||||
|
||||
if (relative)
|
||||
device_input.device->handle_variable(input.usage_page, usage, physical);
|
||||
device_report.device->handle_variable(input.usage_page, usage, physical);
|
||||
else
|
||||
device_input.device->handle_variable_absolute(input.usage_page, usage, physical, input.physical_minimum, input.physical_maximum);
|
||||
device_report.device->handle_variable_absolute(input.usage_page, usage, physical, input.physical_minimum, input.physical_maximum);
|
||||
}
|
||||
|
||||
bit_offset += input.report_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (device_input.device)
|
||||
device_input.device->stop_report();
|
||||
if (device_report.device)
|
||||
device_report.device->stop_report();
|
||||
}
|
||||
}
|
||||
|
||||
void USBHIDDriver::set_leds(uint32_t led_mask)
|
||||
{
|
||||
for (const auto& led_control : m_led_controls)
|
||||
{
|
||||
const size_t report_bytes = BAN::Math::div_round_up<uint32_t>(led_control.report_bits, 8);
|
||||
|
||||
auto led_data = BAN::ByteSpan(reinterpret_cast<uint8_t*>(m_led_region->vaddr()), report_bytes);
|
||||
memset(led_data.data(), 0, report_bytes);
|
||||
|
||||
size_t bit_offset = 0;
|
||||
for (const auto& output : led_control.report->outputs)
|
||||
{
|
||||
if (output.report_id != led_control.report_id)
|
||||
continue;
|
||||
|
||||
const size_t usage_base = output.usage_id ? output.usage_id : output.usage_minimum;
|
||||
for (size_t i = 0; output.report_size == 1 && i < output.report_count; i++, bit_offset++)
|
||||
if (led_mask & (1u << (usage_base + bit_offset)))
|
||||
led_data[bit_offset / 8] |= 1u << (bit_offset % 8);
|
||||
|
||||
bit_offset += output.report_size * output.report_count;
|
||||
}
|
||||
|
||||
USBDeviceRequest request;
|
||||
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Interface;
|
||||
request.bRequest = 0x09;
|
||||
request.wValue = 0x0200 | led_control.report_id;
|
||||
request.wIndex = m_interface.descriptor.bInterfaceNumber;
|
||||
request.wLength = report_bytes;
|
||||
if (auto ret = m_device.send_request(request, m_led_region->paddr()); ret.is_error())
|
||||
dprintln_if(DEBUG_USB_HID, "Failed to update LEDs: {}", ret.error());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,19 +14,10 @@ namespace Kernel
|
||||
static void initialize_scancode_to_keycode();
|
||||
static constexpr bool is_repeatable_scancode(uint8_t scancode);
|
||||
|
||||
USBKeyboard::USBKeyboard(USBHIDDriver& driver, BAN::Vector<USBHID::Report>&& outputs)
|
||||
USBKeyboard::USBKeyboard(USBHIDDriver& driver)
|
||||
: USBHIDDevice(InputDevice::Type::Keyboard)
|
||||
, m_driver(driver)
|
||||
, m_outputs(BAN::move(outputs))
|
||||
{
|
||||
set_leds(0);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> USBKeyboard::initialize()
|
||||
{
|
||||
m_led_region = TRY(DMARegion::create(PAGE_SIZE, PageTable::MemoryType::Normal));
|
||||
return {};
|
||||
}
|
||||
{ }
|
||||
|
||||
void USBKeyboard::start_report()
|
||||
{
|
||||
@@ -114,32 +105,6 @@ namespace Kernel
|
||||
{
|
||||
ASSERT(m_keyboard_lock.current_processor_has_lock());
|
||||
|
||||
if (usage_page != 0x07)
|
||||
{
|
||||
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
|
||||
return;
|
||||
}
|
||||
if (usage >= 4 && usage < m_keyboard_state_temp.size())
|
||||
m_keyboard_state_temp[usage] = true;
|
||||
}
|
||||
|
||||
void USBKeyboard::handle_variable(uint16_t usage_page, uint16_t usage, int64_t state)
|
||||
{
|
||||
(void)usage_page;
|
||||
(void)usage;
|
||||
(void)state;
|
||||
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard relative usage page {2H}", usage_page);
|
||||
}
|
||||
|
||||
void USBKeyboard::handle_variable_absolute(uint16_t usage_page, uint16_t usage, int64_t state, int64_t min, int64_t max)
|
||||
{
|
||||
(void)min; (void)max;
|
||||
|
||||
ASSERT(m_keyboard_lock.current_processor_has_lock());
|
||||
|
||||
if (state == 0)
|
||||
return;
|
||||
|
||||
switch (usage_page)
|
||||
{
|
||||
case 0x07:
|
||||
@@ -149,6 +114,11 @@ namespace Kernel
|
||||
case 0x0C:
|
||||
switch (usage)
|
||||
{
|
||||
case 0x00:
|
||||
break;
|
||||
case 0xE2:
|
||||
m_keyboard_state_temp[0x7F] = true;
|
||||
break;
|
||||
case 0xE9:
|
||||
m_keyboard_state_temp[0x80] = true;
|
||||
break;
|
||||
@@ -166,6 +136,24 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
void USBKeyboard::handle_variable(uint16_t usage_page, uint16_t usage, int64_t state)
|
||||
{
|
||||
(void)usage_page;
|
||||
(void)usage;
|
||||
(void)state;
|
||||
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard relative usage page {2H}", usage_page);
|
||||
}
|
||||
|
||||
void USBKeyboard::handle_variable_absolute(uint16_t usage_page, uint16_t usage, int64_t state, int64_t min, int64_t max)
|
||||
{
|
||||
(void)min; (void)max;
|
||||
|
||||
if (state == 0)
|
||||
return;
|
||||
|
||||
handle_array(usage_page, usage);
|
||||
}
|
||||
|
||||
void USBKeyboard::update()
|
||||
{
|
||||
using KeyModifier = LibInput::KeyEvent::Modifier;
|
||||
@@ -173,8 +161,19 @@ namespace Kernel
|
||||
const auto toggle_mask = ({ SpinLockGuard _(m_keyboard_lock); m_toggle_mask; });
|
||||
|
||||
if (m_led_mask != toggle_mask)
|
||||
set_leds(toggle_mask);
|
||||
{
|
||||
uint32_t usb_led_mask { 0 };
|
||||
if (toggle_mask & KeyModifier::NumLock)
|
||||
usb_led_mask |= 1 << 1;
|
||||
if (toggle_mask & KeyModifier::CapsLock)
|
||||
usb_led_mask |= 1 << 2;
|
||||
if (toggle_mask & KeyModifier::ScrollLock)
|
||||
usb_led_mask |= 1 << 3;
|
||||
|
||||
m_driver.device().update_led_mask(usb_led_mask);
|
||||
|
||||
m_led_mask = toggle_mask;
|
||||
}
|
||||
|
||||
SpinLockGuard _(m_keyboard_lock);
|
||||
|
||||
@@ -193,88 +192,6 @@ namespace Kernel
|
||||
m_next_repeat_event_ms += s_repeat_interval_ms;
|
||||
}
|
||||
|
||||
void USBKeyboard::set_leds(uint16_t mask)
|
||||
{
|
||||
uint8_t report_ids_done[0x100 / 8] {};
|
||||
|
||||
for (const auto& report : m_outputs)
|
||||
{
|
||||
if (report.usage_page != 0x08)
|
||||
continue;
|
||||
|
||||
const auto byte = report.report_id / 8;
|
||||
const auto bit = report.report_id % 8;
|
||||
if (report_ids_done[byte] & (1u << bit))
|
||||
continue;
|
||||
|
||||
set_leds(report.report_id, mask);
|
||||
report_ids_done[byte] |= (1u << bit);
|
||||
}
|
||||
}
|
||||
|
||||
void USBKeyboard::set_leds(uint8_t report_id, uint16_t mask)
|
||||
{
|
||||
using KeyModifier = LibInput::KeyEvent::Modifier;
|
||||
|
||||
if (!m_led_region)
|
||||
return;
|
||||
|
||||
size_t report_bits = 0;
|
||||
for (const auto& report : m_outputs)
|
||||
{
|
||||
if (report.report_id != report_id)
|
||||
continue;
|
||||
report_bits += report.report_size * report.report_count;
|
||||
}
|
||||
|
||||
const size_t report_bytes = (report_bits + 7) / 8;
|
||||
ASSERT(report_bytes <= PAGE_SIZE);
|
||||
|
||||
PageTable::with_fast_page(m_led_region->paddr(), [&] {
|
||||
uint8_t* data = &PageTable::fast_page_as<uint8_t>();
|
||||
|
||||
memset(data, 0, report_bytes);
|
||||
|
||||
size_t bit_offset = 0;
|
||||
for (const auto& report : m_outputs)
|
||||
{
|
||||
if (report.report_id != report_id)
|
||||
continue;
|
||||
|
||||
for (size_t i = 0; report.report_size == 1 && i < report.report_count; i++, bit_offset++)
|
||||
{
|
||||
const size_t usage = (report.usage_id ? report.usage_id : report.usage_minimum) + bit_offset;
|
||||
switch (usage)
|
||||
{
|
||||
case 0x01:
|
||||
if (mask & KeyModifier::NumLock)
|
||||
data[bit_offset / 8] |= 1u << (bit_offset % 8);
|
||||
break;
|
||||
case 0x02:
|
||||
if (mask & KeyModifier::CapsLock)
|
||||
data[bit_offset / 8] |= 1u << (bit_offset % 8);
|
||||
break;
|
||||
case 0x03:
|
||||
if (mask & KeyModifier::ScrollLock)
|
||||
data[bit_offset / 8] |= 1u << (bit_offset % 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bit_offset += report.report_size * report.report_count;
|
||||
}
|
||||
});
|
||||
|
||||
USBDeviceRequest request;
|
||||
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Interface;
|
||||
request.bRequest = 0x09;
|
||||
request.wValue = 0x0200 | report_id;
|
||||
request.wIndex = m_driver.interface().descriptor.bInterfaceNumber;
|
||||
request.wLength = report_bytes;
|
||||
if (auto ret = m_driver.device().send_request(request, m_led_region->paddr()); ret.is_error())
|
||||
dprintln_if(DEBUG_USB_KEYBOARD, "Failed to update LEDs: {}", ret.error());
|
||||
}
|
||||
|
||||
void initialize_scancode_to_keycode()
|
||||
{
|
||||
using LibInput::keycode_function;
|
||||
@@ -324,6 +241,7 @@ namespace Kernel
|
||||
s_scancode_to_keycode[0x33] = keycode_normal(2, 10);
|
||||
s_scancode_to_keycode[0x34] = keycode_normal(2, 11);
|
||||
s_scancode_to_keycode[0x31] = keycode_normal(2, 12);
|
||||
s_scancode_to_keycode[0x32] = keycode_normal(2, 12);
|
||||
s_scancode_to_keycode[0x28] = keycode_normal(2, 13);
|
||||
s_scancode_to_keycode[0xE1] = keycode_normal(3, 0);
|
||||
s_scancode_to_keycode[0x64] = keycode_normal(3, 1);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include <BAN/ScopeGuard.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
#include <kernel/USB/Hub/Definitions.h>
|
||||
#include <kernel/USB/Hub/HubDriver.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
@@ -192,7 +194,7 @@ namespace Kernel
|
||||
auto result = m_device.send_request(request, m_data_region->paddr());
|
||||
if (result.is_error() || result.value() != sizeof(USBHub::PortStatus))
|
||||
{
|
||||
dwarnln("Failed to get port {} status");
|
||||
dwarnln("Failed to get port {} status", port_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user