Compare commits
9 Commits
c84a30d4dd
...
fc0f3157ea
| Author | SHA1 | Date |
|---|---|---|
|
|
fc0f3157ea | |
|
|
a9ceab0415 | |
|
|
94bd74d0bb | |
|
|
b2d8199480 | |
|
|
e60f3711f8 | |
|
|
6ec9e4f7b8 | |
|
|
9eb3834ae5 | |
|
|
ee57cf3e9a | |
|
|
fea5d1d82b |
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Iteration.h>
|
#include <BAN/Iterators.h>
|
||||||
#include <BAN/Swap.h>
|
#include <BAN/Swap.h>
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,7 @@ asm_syscall_handler:
|
||||||
andl $-16, %esp
|
andl $-16, %esp
|
||||||
|
|
||||||
# push arguments
|
# push arguments
|
||||||
subl $4, %esp
|
subl $8, %esp
|
||||||
pushl %ebp
|
|
||||||
addl $24, (%esp)
|
|
||||||
pushl %edi
|
pushl %edi
|
||||||
pushl %esi
|
pushl %esi
|
||||||
pushl %edx
|
pushl %edx
|
||||||
|
|
@ -65,7 +63,7 @@ sys_fork_trampoline:
|
||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testl %eax, %eax
|
testl %eax, %eax
|
||||||
jz .reload_stack
|
jz .done
|
||||||
|
|
||||||
movl %esp, %ebx
|
movl %esp, %ebx
|
||||||
|
|
||||||
|
|
@ -81,9 +79,3 @@ sys_fork_trampoline:
|
||||||
popl %ebx
|
popl %ebx
|
||||||
popl %ebp
|
popl %ebp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.reload_stack:
|
|
||||||
call get_thread_start_sp
|
|
||||||
movl %eax, %esp
|
|
||||||
xorl %eax, %eax
|
|
||||||
jmp .done
|
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,13 @@ enable_sse:
|
||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
enable_tsc:
|
||||||
|
# allow userspace to use RDTSC
|
||||||
|
movl %cr4, %ecx
|
||||||
|
andl $0xFFFFFFFB, %ecx
|
||||||
|
movl %ecx, %cr4
|
||||||
|
ret
|
||||||
|
|
||||||
initialize_paging:
|
initialize_paging:
|
||||||
# enable PAE
|
# enable PAE
|
||||||
movl %cr4, %ecx
|
movl %cr4, %ecx
|
||||||
|
|
@ -226,6 +233,7 @@ gdt_flush:
|
||||||
# do processor initialization
|
# do processor initialization
|
||||||
call check_requirements
|
call check_requirements
|
||||||
call enable_sse
|
call enable_sse
|
||||||
|
call enable_tsc
|
||||||
call initialize_paging
|
call initialize_paging
|
||||||
|
|
||||||
# load higher half stack pointer
|
# load higher half stack pointer
|
||||||
|
|
@ -302,6 +310,7 @@ ap_protected_mode:
|
||||||
movb $1, AP_V2P(ap_stack_loaded)
|
movb $1, AP_V2P(ap_stack_loaded)
|
||||||
|
|
||||||
leal V2P(enable_sse), %ecx; call *%ecx
|
leal V2P(enable_sse), %ecx; call *%ecx
|
||||||
|
leal V2P(enable_tsc), %ecx; call *%ecx
|
||||||
leal V2P(initialize_paging), %ecx; call *%ecx
|
leal V2P(initialize_paging), %ecx; call *%ecx
|
||||||
|
|
||||||
# load boot gdt and enter long mode
|
# load boot gdt and enter long mode
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
.macro maybe_load_kernel_segments, n
|
.macro maybe_load_kernel_segments, n
|
||||||
cmpb $0x08, \n(%esp)
|
testb $3, \n(%esp)
|
||||||
je 1f
|
jz 1f; jnp 1f
|
||||||
|
|
||||||
movw $0x10, %ax
|
movw $0x10, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
|
|
@ -13,8 +13,8 @@
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro maybe_load_userspace_segments, n
|
.macro maybe_load_userspace_segments, n
|
||||||
cmpb $0x08, \n(%esp)
|
testb $3, \n(%esp)
|
||||||
je 1f
|
jz 1f; jnp 1f
|
||||||
|
|
||||||
movw $(0x20 | 3), %bx
|
movw $(0x20 | 3), %bx
|
||||||
movw %bx, %ds
|
movw %bx, %ds
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,26 @@
|
||||||
// arguments in RAX, RBX, RCX, RDX, RSI, RDI
|
|
||||||
// System V ABI: RDI, RSI, RDX, RCX, R8, R9
|
|
||||||
.global asm_syscall_handler
|
.global asm_syscall_handler
|
||||||
asm_syscall_handler:
|
asm_syscall_handler:
|
||||||
swapgs
|
swapgs
|
||||||
pushq %rbx
|
|
||||||
pushq %rcx
|
movq %rsp, %rax
|
||||||
pushq %rdx
|
movq %gs:8, %rsp
|
||||||
pushq %rdi
|
|
||||||
pushq %rsi
|
pushq $(0x20 | 3)
|
||||||
pushq %rbp
|
pushq %rax
|
||||||
pushq %r8
|
|
||||||
pushq %r9
|
|
||||||
pushq %r10
|
|
||||||
pushq %r11
|
pushq %r11
|
||||||
pushq %r12
|
pushq $(0x28 | 3)
|
||||||
pushq %r13
|
pushq %rcx
|
||||||
pushq %r14
|
subq $8, %rsp
|
||||||
pushq %r15
|
|
||||||
cld
|
|
||||||
|
|
||||||
movq %rsi, %r8
|
movq %r10, %rcx
|
||||||
movq %rdi, %r9
|
|
||||||
movq %rax, %rdi
|
|
||||||
movq %rbx, %rsi
|
|
||||||
xchgq %rcx, %rdx
|
|
||||||
leaq 112(%rsp), %rbx
|
|
||||||
pushq %rbx
|
|
||||||
call cpp_syscall_handler
|
call cpp_syscall_handler
|
||||||
addq $8, %rsp
|
|
||||||
|
|
||||||
popq %r15
|
movq 8(%rsp), %rcx
|
||||||
popq %r14
|
movq 24(%rsp), %r11
|
||||||
popq %r13
|
movq 32(%rsp), %rsp
|
||||||
popq %r12
|
|
||||||
popq %r11
|
|
||||||
popq %r10
|
|
||||||
popq %r9
|
|
||||||
popq %r8
|
|
||||||
popq %rbp
|
|
||||||
popq %rsi
|
|
||||||
popq %rdi
|
|
||||||
popq %rdx
|
|
||||||
popq %rcx
|
|
||||||
popq %rbx
|
|
||||||
swapgs
|
swapgs
|
||||||
iretq
|
sysretq
|
||||||
|
|
||||||
.global sys_fork_trampoline
|
.global sys_fork_trampoline
|
||||||
sys_fork_trampoline:
|
sys_fork_trampoline:
|
||||||
|
|
@ -57,7 +33,7 @@ sys_fork_trampoline:
|
||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testq %rax, %rax
|
testq %rax, %rax
|
||||||
je .reload_stack
|
je .done
|
||||||
|
|
||||||
movq %rax, %rsi
|
movq %rax, %rsi
|
||||||
movq %rsp, %rdi
|
movq %rsp, %rdi
|
||||||
|
|
@ -71,9 +47,3 @@ sys_fork_trampoline:
|
||||||
popq %rbp
|
popq %rbp
|
||||||
popq %rbx
|
popq %rbx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.reload_stack:
|
|
||||||
call get_thread_start_sp
|
|
||||||
movq %rax, %rsp
|
|
||||||
xorq %rax, %rax
|
|
||||||
jmp .done
|
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,13 @@ enable_sse:
|
||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
enable_tsc:
|
||||||
|
# allow userspace to use RDTSC
|
||||||
|
movl %cr4, %ecx
|
||||||
|
andl $0xFFFFFFFB, %ecx
|
||||||
|
movl %ecx, %cr4
|
||||||
|
ret
|
||||||
|
|
||||||
initialize_paging:
|
initialize_paging:
|
||||||
# enable PAE
|
# enable PAE
|
||||||
movl %cr4, %ecx
|
movl %cr4, %ecx
|
||||||
|
|
@ -215,6 +222,7 @@ _start:
|
||||||
|
|
||||||
call check_requirements
|
call check_requirements
|
||||||
call enable_sse
|
call enable_sse
|
||||||
|
call enable_tsc
|
||||||
call initialize_paging
|
call initialize_paging
|
||||||
|
|
||||||
# flush gdt and jump to 64 bit
|
# flush gdt and jump to 64 bit
|
||||||
|
|
@ -301,6 +309,7 @@ ap_protected_mode:
|
||||||
movb $1, AP_V2P(ap_stack_loaded)
|
movb $1, AP_V2P(ap_stack_loaded)
|
||||||
|
|
||||||
leal V2P(enable_sse), %ecx; call *%ecx
|
leal V2P(enable_sse), %ecx; call *%ecx
|
||||||
|
leal V2P(enable_tsc), %ecx; call *%ecx
|
||||||
leal V2P(initialize_paging), %ecx; call *%ecx
|
leal V2P(initialize_paging), %ecx; call *%ecx
|
||||||
|
|
||||||
# load boot gdt and enter long mode
|
# load boot gdt and enter long mode
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
.macro swapgs_if_necessary, n
|
.macro swapgs_if_necessary, n
|
||||||
cmpb $0x08, \n(%rsp)
|
testb $3, \n(%rsp)
|
||||||
je 1f
|
jz 1f; jnp 1f
|
||||||
swapgs
|
swapgs
|
||||||
1:
|
1:
|
||||||
.endm
|
.endm
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Kernel::API
|
||||||
|
{
|
||||||
|
|
||||||
|
enum SharedPageFeature : uint32_t
|
||||||
|
{
|
||||||
|
SPF_GETTIME = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SharedPage
|
||||||
|
{
|
||||||
|
uint8_t __sequence[0x100];
|
||||||
|
|
||||||
|
uint32_t features;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t shift;
|
||||||
|
uint64_t mult;
|
||||||
|
uint64_t realtime_seconds;
|
||||||
|
} gettime_shared;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t seq;
|
||||||
|
uint64_t last_ns;
|
||||||
|
uint64_t last_tsc;
|
||||||
|
} gettime_local;
|
||||||
|
} cpus[];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/Attributes.h>
|
||||||
|
#include <kernel/IDT.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
ALWAYS_INLINE long syscall(int syscall, uintptr_t arg1 = 0, uintptr_t arg2 = 0, uintptr_t arg3 = 0, uintptr_t arg4 = 0, uintptr_t arg5 = 0)
|
||||||
|
{
|
||||||
|
long ret;
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
register uintptr_t r10 asm("r10") = arg3;
|
||||||
|
register uintptr_t r8 asm( "r8") = arg4;
|
||||||
|
register uintptr_t r9 asm( "r9") = arg5;
|
||||||
|
asm volatile(
|
||||||
|
"syscall"
|
||||||
|
: "=a"(ret)
|
||||||
|
, "+D"(syscall)
|
||||||
|
, "+S"(arg1)
|
||||||
|
, "+d"(arg2)
|
||||||
|
, "+r"(r10)
|
||||||
|
, "+r"(r8)
|
||||||
|
, "+r"(r9)
|
||||||
|
:: "rcx", "r11", "memory");
|
||||||
|
#elif ARCH(i686)
|
||||||
|
asm volatile(
|
||||||
|
"int %[irq]"
|
||||||
|
: "=a"(ret)
|
||||||
|
: [irq]"i"(static_cast<int>(IRQ_SYSCALL)) // WTF GCC 15
|
||||||
|
, "a"(syscall)
|
||||||
|
, "b"(arg1)
|
||||||
|
, "c"(arg2)
|
||||||
|
, "d"(arg3)
|
||||||
|
, "S"(arg4)
|
||||||
|
, "D"(arg5)
|
||||||
|
: "memory");
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -81,5 +81,6 @@ namespace CPUID
|
||||||
bool has_pge();
|
bool has_pge();
|
||||||
bool has_pat();
|
bool has_pat();
|
||||||
bool has_1gib_pages();
|
bool has_1gib_pages();
|
||||||
|
bool has_invariant_tsc();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,8 +151,8 @@ namespace Kernel
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
BAN::Array<SegmentDescriptor, 7> m_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
|
BAN::Array<SegmentDescriptor, 8> m_gdt; // null, kernel code, kernel data, user code (32 bit), user data, user code (64 bit), tss low, tss high
|
||||||
static constexpr uint16_t m_tss_offset = 0x28;
|
static constexpr uint16_t m_tss_offset = 0x30;
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
BAN::Array<SegmentDescriptor, 9> m_gdt; // null, kernel code, kernel data, user code, user data, processor data, fsbase, gsbase, tss
|
BAN::Array<SegmentDescriptor, 9> m_gdt; // null, kernel code, kernel data, user code, user data, processor data, fsbase, gsbase, tss
|
||||||
static constexpr uint16_t m_tss_offset = 0x40;
|
static constexpr uint16_t m_tss_offset = 0x40;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,10 @@ namespace Kernel
|
||||||
|
|
||||||
constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
|
constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
|
||||||
constexpr uint8_t IRQ_MSI_BASE = 0x80;
|
constexpr uint8_t IRQ_MSI_BASE = 0x80;
|
||||||
|
constexpr uint8_t IRQ_MSI_END = 0xF0;
|
||||||
|
#if ARCH(i686)
|
||||||
constexpr uint8_t IRQ_SYSCALL = 0xF0;
|
constexpr uint8_t IRQ_SYSCALL = 0xF0;
|
||||||
|
#endif
|
||||||
constexpr uint8_t IRQ_YIELD = 0xF1;
|
constexpr uint8_t IRQ_YIELD = 0xF1;
|
||||||
constexpr uint8_t IRQ_IPI = 0xF2;
|
constexpr uint8_t IRQ_IPI = 0xF2;
|
||||||
constexpr uint8_t IRQ_TIMER = 0xF3;
|
constexpr uint8_t IRQ_TIMER = 0xF3;
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ namespace Kernel::PCI
|
||||||
void initialize_impl();
|
void initialize_impl();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint8_t m_msi_count = IRQ_SYSCALL - IRQ_MSI_BASE;
|
static constexpr uint8_t m_msi_count = IRQ_MSI_END - IRQ_MSI_BASE;
|
||||||
using PCIBus = BAN::Array<BAN::Array<Device, 8>, 32>;
|
using PCIBus = BAN::Array<BAN::Array<Device, 8>, 32>;
|
||||||
BAN::Array<PCIBus, 256> m_buses;
|
BAN::Array<PCIBus, 256> m_buses;
|
||||||
BAN::Array<paddr_t, 256> m_bus_pcie_paddr;
|
BAN::Array<paddr_t, 256> m_bus_pcie_paddr;
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,8 @@ namespace Kernel
|
||||||
|
|
||||||
static Process& current() { return Thread::current().process(); }
|
static Process& current() { return Thread::current().process(); }
|
||||||
|
|
||||||
|
vaddr_t shared_page_vaddr() const { return m_shared_page_vaddr; }
|
||||||
|
|
||||||
PageTable& page_table() { return m_page_table ? *m_page_table : PageTable::kernel(); }
|
PageTable& page_table() { return m_page_table ? *m_page_table : PageTable::kernel(); }
|
||||||
|
|
||||||
size_t proc_meminfo(off_t offset, BAN::ByteSpan) const;
|
size_t proc_meminfo(off_t offset, BAN::ByteSpan) const;
|
||||||
|
|
@ -342,6 +344,8 @@ namespace Kernel
|
||||||
VirtualFileSystem::File m_working_directory;
|
VirtualFileSystem::File m_working_directory;
|
||||||
VirtualFileSystem::File m_root_file;
|
VirtualFileSystem::File m_root_file;
|
||||||
|
|
||||||
|
vaddr_t m_shared_page_vaddr { 0 };
|
||||||
|
|
||||||
BAN::Vector<Thread*> m_threads;
|
BAN::Vector<Thread*> m_threads;
|
||||||
|
|
||||||
struct pthread_info_t
|
struct pthread_info_t
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,12 @@
|
||||||
#include <BAN/Atomic.h>
|
#include <BAN/Atomic.h>
|
||||||
#include <BAN/ForwardList.h>
|
#include <BAN/ForwardList.h>
|
||||||
|
|
||||||
|
#include <kernel/API/SharedPage.h>
|
||||||
#include <kernel/Arch.h>
|
#include <kernel/Arch.h>
|
||||||
#include <kernel/GDT.h>
|
#include <kernel/GDT.h>
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/InterruptStack.h>
|
#include <kernel/InterruptStack.h>
|
||||||
|
#include <kernel/Memory/Types.h>
|
||||||
#include <kernel/ProcessorID.h>
|
#include <kernel/ProcessorID.h>
|
||||||
#include <kernel/Scheduler.h>
|
#include <kernel/Scheduler.h>
|
||||||
|
|
||||||
|
|
@ -33,6 +35,7 @@ namespace Kernel
|
||||||
FlushTLB,
|
FlushTLB,
|
||||||
NewThread,
|
NewThread,
|
||||||
UnblockThread,
|
UnblockThread,
|
||||||
|
UpdateTSC,
|
||||||
StackTrace,
|
StackTrace,
|
||||||
};
|
};
|
||||||
SMPMessage* next { nullptr };
|
SMPMessage* next { nullptr };
|
||||||
|
|
@ -55,6 +58,7 @@ namespace Kernel
|
||||||
static Processor& initialize();
|
static Processor& initialize();
|
||||||
|
|
||||||
static ProcessorID current_id() { return read_gs_sized<ProcessorID>(offsetof(Processor, m_id)); }
|
static ProcessorID current_id() { return read_gs_sized<ProcessorID>(offsetof(Processor, m_id)); }
|
||||||
|
static uint8_t current_index() { return read_gs_sized<uint8_t>(offsetof(Processor, m_index)); }
|
||||||
static ProcessorID id_from_index(size_t index);
|
static ProcessorID id_from_index(size_t index);
|
||||||
|
|
||||||
static uint8_t count() { return s_processor_count; }
|
static uint8_t count() { return s_processor_count; }
|
||||||
|
|
@ -78,8 +82,11 @@ namespace Kernel
|
||||||
|
|
||||||
static InterruptState get_interrupt_state()
|
static InterruptState get_interrupt_state()
|
||||||
{
|
{
|
||||||
uintptr_t flags;
|
#if ARCH(x86_64)
|
||||||
asm volatile("pushf; pop %0" : "=rm"(flags));
|
const auto flags = __builtin_ia32_readeflags_u64();
|
||||||
|
#elif ARCH(i686)
|
||||||
|
const auto flags = __builtin_ia32_readeflags_u32();
|
||||||
|
#endif
|
||||||
if (flags & (1 << 9))
|
if (flags & (1 << 9))
|
||||||
return InterruptState::Enabled;
|
return InterruptState::Enabled;
|
||||||
return InterruptState::Disabled;
|
return InterruptState::Disabled;
|
||||||
|
|
@ -98,6 +105,8 @@ namespace Kernel
|
||||||
uintptr_t stack_bottom() const { return reinterpret_cast<uintptr_t>(m_stack); }
|
uintptr_t stack_bottom() const { return reinterpret_cast<uintptr_t>(m_stack); }
|
||||||
uintptr_t stack_top() const { return stack_bottom() + s_stack_size; }
|
uintptr_t stack_top() const { return stack_bottom() + s_stack_size; }
|
||||||
|
|
||||||
|
static void set_thread_syscall_stack(vaddr_t vaddr) { write_gs_sized<vaddr_t>(offsetof(Processor, m_thread_syscall_stack), vaddr); }
|
||||||
|
|
||||||
static GDT& gdt() { return *read_gs_sized<GDT*>(offsetof(Processor, m_gdt)); }
|
static GDT& gdt() { return *read_gs_sized<GDT*>(offsetof(Processor, m_gdt)); }
|
||||||
static IDT& idt() { return *read_gs_sized<IDT*>(offsetof(Processor, m_idt)); }
|
static IDT& idt() { return *read_gs_sized<IDT*>(offsetof(Processor, m_idt)); }
|
||||||
|
|
||||||
|
|
@ -107,6 +116,13 @@ namespace Kernel
|
||||||
static void yield();
|
static void yield();
|
||||||
static Scheduler& scheduler() { return *read_gs_sized<Scheduler*>(offsetof(Processor, m_scheduler)); }
|
static Scheduler& scheduler() { return *read_gs_sized<Scheduler*>(offsetof(Processor, m_scheduler)); }
|
||||||
|
|
||||||
|
static void initialize_tsc(uint8_t shift, uint64_t mult, uint64_t realtime_seconds);
|
||||||
|
static void update_tsc();
|
||||||
|
static uint64_t ns_since_boot_tsc();
|
||||||
|
|
||||||
|
static paddr_t shared_page_paddr() { return s_shared_page_paddr; }
|
||||||
|
static volatile API::SharedPage& shared_page() { return *reinterpret_cast<API::SharedPage*>(s_shared_page_vaddr); }
|
||||||
|
|
||||||
static void handle_ipi();
|
static void handle_ipi();
|
||||||
|
|
||||||
static void handle_smp_messages();
|
static void handle_smp_messages();
|
||||||
|
|
@ -124,6 +140,14 @@ namespace Kernel
|
||||||
static ProcessorID read_processor_id();
|
static ProcessorID read_processor_id();
|
||||||
|
|
||||||
static void initialize_smp();
|
static void initialize_smp();
|
||||||
|
static void initialize_shared_page();
|
||||||
|
|
||||||
|
static void dummy()
|
||||||
|
{
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
static_assert(offsetof(Processor, m_thread_syscall_stack) == 8, "This is hardcoded in Syscall.S");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8)
|
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8)
|
||||||
|
|
@ -162,8 +186,13 @@ namespace Kernel
|
||||||
static BAN::Atomic<uint8_t> s_processor_count;
|
static BAN::Atomic<uint8_t> s_processor_count;
|
||||||
static BAN::Atomic<bool> s_is_smp_enabled;
|
static BAN::Atomic<bool> s_is_smp_enabled;
|
||||||
static BAN::Atomic<bool> s_should_print_cpu_load;
|
static BAN::Atomic<bool> s_should_print_cpu_load;
|
||||||
|
static paddr_t s_shared_page_paddr;
|
||||||
|
static vaddr_t s_shared_page_vaddr;
|
||||||
|
|
||||||
ProcessorID m_id { 0 };
|
ProcessorID m_id { 0 };
|
||||||
|
uint8_t m_index { 0xFF };
|
||||||
|
|
||||||
|
vaddr_t m_thread_syscall_stack;
|
||||||
|
|
||||||
static constexpr size_t s_stack_size { 4096 };
|
static constexpr size_t s_stack_size { 4096 };
|
||||||
void* m_stack { nullptr };
|
void* m_stack { nullptr };
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <kernel/Attributes.h>
|
|
||||||
#include <kernel/IDT.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
ALWAYS_INLINE long syscall(int syscall, uintptr_t arg1 = 0, uintptr_t arg2 = 0, uintptr_t arg3 = 0, uintptr_t arg4 = 0, uintptr_t arg5 = 0)
|
|
||||||
{
|
|
||||||
long ret;
|
|
||||||
asm volatile("int %[irq]"
|
|
||||||
: "=a"(ret)
|
|
||||||
: [irq]"i"(static_cast<int>(IRQ_SYSCALL)) // WTF GCC 15
|
|
||||||
, "a"(syscall)
|
|
||||||
, "b"((uintptr_t)arg1)
|
|
||||||
, "c"((uintptr_t)arg2)
|
|
||||||
, "d"((uintptr_t)arg3)
|
|
||||||
, "S"((uintptr_t)arg4)
|
|
||||||
, "D"((uintptr_t)arg5)
|
|
||||||
: "memory");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -122,6 +122,8 @@ namespace Kernel
|
||||||
void set_cpu_time_start();
|
void set_cpu_time_start();
|
||||||
void set_cpu_time_stop();
|
void set_cpu_time_stop();
|
||||||
|
|
||||||
|
void update_processor_index_address();
|
||||||
|
|
||||||
void set_fsbase(vaddr_t base) { m_fsbase = base; }
|
void set_fsbase(vaddr_t base) { m_fsbase = base; }
|
||||||
vaddr_t get_fsbase() const { return m_fsbase; }
|
vaddr_t get_fsbase() const { return m_fsbase; }
|
||||||
void set_gsbase(vaddr_t base) { m_gsbase = base; }
|
void set_gsbase(vaddr_t base) { m_gsbase = base; }
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ namespace Kernel
|
||||||
static SystemTimer& get();
|
static SystemTimer& get();
|
||||||
static bool is_initialized();
|
static bool is_initialized();
|
||||||
|
|
||||||
|
void initialize_tsc();
|
||||||
|
|
||||||
virtual uint64_t ms_since_boot() const override;
|
virtual uint64_t ms_since_boot() const override;
|
||||||
virtual uint64_t ns_since_boot() const override;
|
virtual uint64_t ns_since_boot() const override;
|
||||||
virtual timespec time_since_boot() const override;
|
virtual timespec time_since_boot() const override;
|
||||||
|
|
@ -47,6 +49,9 @@ namespace Kernel
|
||||||
|
|
||||||
void dont_invoke_scheduler() { m_timer->m_should_invoke_scheduler = false; }
|
void dont_invoke_scheduler() { m_timer->m_should_invoke_scheduler = false; }
|
||||||
|
|
||||||
|
void update_tsc() const;
|
||||||
|
uint64_t ns_since_boot_no_tsc() const;
|
||||||
|
|
||||||
timespec real_time() const;
|
timespec real_time() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -54,10 +59,14 @@ namespace Kernel
|
||||||
|
|
||||||
void initialize_timers(bool force_pic);
|
void initialize_timers(bool force_pic);
|
||||||
|
|
||||||
|
uint64_t get_tsc_frequency() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t m_boot_time { 0 };
|
uint64_t m_boot_time { 0 };
|
||||||
BAN::UniqPtr<RTC> m_rtc;
|
BAN::UniqPtr<RTC> m_rtc;
|
||||||
BAN::UniqPtr<Timer> m_timer;
|
BAN::UniqPtr<Timer> m_timer;
|
||||||
|
bool m_has_invariant_tsc { false };
|
||||||
|
mutable uint32_t m_timer_ticks { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize();
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
|
const USBDeviceDescriptor& device_descriptor() const { return m_descriptor.descriptor; }
|
||||||
const BAN::Vector<ConfigurationDescriptor>& configurations() { return m_descriptor.configurations; }
|
const BAN::Vector<ConfigurationDescriptor>& configurations() { return m_descriptor.configurations; }
|
||||||
|
|
||||||
virtual BAN::ErrorOr<uint8_t> initialize_device_on_hub_port(uint8_t port_id, USB::SpeedClass) = 0;
|
virtual BAN::ErrorOr<uint8_t> initialize_device_on_hub_port(uint8_t port_id, USB::SpeedClass) = 0;
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,16 @@ namespace CPUID
|
||||||
return buffer[3] & (1 << 26);
|
return buffer[3] & (1 << 26);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_invariant_tsc()
|
||||||
|
{
|
||||||
|
uint32_t buffer[4] {};
|
||||||
|
get_cpuid(0x80000000, buffer);
|
||||||
|
if (buffer[0] < 0x80000007)
|
||||||
|
return false;
|
||||||
|
get_cpuid(0x80000007, buffer);
|
||||||
|
return buffer[3] & (1 << 8);
|
||||||
|
}
|
||||||
|
|
||||||
const char* feature_string_ecx(uint32_t feat)
|
const char* feature_string_ecx(uint32_t feat)
|
||||||
{
|
{
|
||||||
switch (feat)
|
switch (feat)
|
||||||
|
|
|
||||||
|
|
@ -15,23 +15,23 @@ namespace Kernel
|
||||||
ASSERT(gdt);
|
ASSERT(gdt);
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
constexpr uint8_t code_flags = 0xA;
|
gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||||
constexpr uint8_t data_flags = 0xC;
|
gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
|
||||||
|
gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
||||||
|
gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xC); // user code (32 bit)
|
||||||
|
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||||
|
gdt->write_entry(0x28, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code (64 bit)
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
constexpr uint8_t code_flags = 0xC;
|
gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||||
constexpr uint8_t data_flags = 0xC;
|
gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xC); // kernel code
|
||||||
|
gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
||||||
|
gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xC); // user code
|
||||||
|
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||||
|
gdt->write_entry(0x28, reinterpret_cast<uint32_t>(processor), sizeof(Processor), 0x92, 0x4); // processor data
|
||||||
|
gdt->write_entry(0x30, 0x00000000, 0x00000, 0xF2, 0xC); // fsbase
|
||||||
|
gdt->write_entry(0x38, 0x00000000, 0x00000, 0xF2, 0xC); // gsbase
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
|
||||||
gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, code_flags); // kernel code
|
|
||||||
gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, data_flags); // kernel data
|
|
||||||
gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, code_flags); // user code
|
|
||||||
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, data_flags); // user data
|
|
||||||
#if ARCH(i686)
|
|
||||||
gdt->write_entry(0x28, reinterpret_cast<uint32_t>(processor), sizeof(Processor), 0x92, 0x4); // processor data
|
|
||||||
gdt->write_entry(0x30, 0x00000000, 0x00000, 0xF2, data_flags); // fsbase
|
|
||||||
gdt->write_entry(0x38, 0x00000000, 0x00000, 0xF2, data_flags); // gsbase
|
|
||||||
#endif
|
|
||||||
gdt->write_tss();
|
gdt->write_tss();
|
||||||
|
|
||||||
return gdt;
|
return gdt;
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@
|
||||||
X(160) X(161) X(162) X(163) X(164) X(165) X(166) X(167) X(168) X(169) X(170) X(171) X(172) X(173) X(174) X(175) X(176) X(177) X(178) X(179) X(180) X(181) X(182) X(183) X(184) X(185) X(186) X(187) X(188) X(189) X(190) X(191) \
|
X(160) X(161) X(162) X(163) X(164) X(165) X(166) X(167) X(168) X(169) X(170) X(171) X(172) X(173) X(174) X(175) X(176) X(177) X(178) X(179) X(180) X(181) X(182) X(183) X(184) X(185) X(186) X(187) X(188) X(189) X(190) X(191) \
|
||||||
X(192) X(193) X(194) X(195) X(196) X(197) X(198) X(199) X(200) X(201) X(202) X(203) X(204) X(205) X(206) X(207)
|
X(192) X(193) X(194) X(195) X(196) X(197) X(198) X(199) X(200) X(201) X(202) X(203) X(204) X(205) X(206) X(207)
|
||||||
|
|
||||||
static_assert(Kernel::IRQ_SYSCALL == Kernel::IRQ_VECTOR_BASE + 208);
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -446,7 +444,9 @@ namespace Kernel
|
||||||
extern "C" void asm_yield_handler();
|
extern "C" void asm_yield_handler();
|
||||||
extern "C" void asm_ipi_handler();
|
extern "C" void asm_ipi_handler();
|
||||||
extern "C" void asm_timer_handler();
|
extern "C" void asm_timer_handler();
|
||||||
|
#if ARCH(i686)
|
||||||
extern "C" void asm_syscall_handler();
|
extern "C" void asm_syscall_handler();
|
||||||
|
#endif
|
||||||
|
|
||||||
IDT* IDT::create()
|
IDT* IDT::create()
|
||||||
{
|
{
|
||||||
|
|
@ -480,7 +480,9 @@ namespace Kernel
|
||||||
idt->register_interrupt_handler(IRQ_YIELD, asm_yield_handler);
|
idt->register_interrupt_handler(IRQ_YIELD, asm_yield_handler);
|
||||||
idt->register_interrupt_handler(IRQ_IPI, asm_ipi_handler);
|
idt->register_interrupt_handler(IRQ_IPI, asm_ipi_handler);
|
||||||
idt->register_interrupt_handler(IRQ_TIMER, asm_timer_handler);
|
idt->register_interrupt_handler(IRQ_TIMER, asm_timer_handler);
|
||||||
|
#if ARCH(i686)
|
||||||
idt->register_syscall_handler(IRQ_SYSCALL, asm_syscall_handler);
|
idt->register_syscall_handler(IRQ_SYSCALL, asm_syscall_handler);
|
||||||
|
#endif
|
||||||
|
|
||||||
return idt;
|
return idt;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,20 @@ namespace Kernel
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process->m_shared_page_vaddr = process->page_table().reserve_free_page(process->m_mapped_regions.back()->vaddr(), USERSPACE_END);
|
||||||
|
if (process->m_shared_page_vaddr == 0)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
process->page_table().map_page_at(
|
||||||
|
Processor::shared_page_paddr(),
|
||||||
|
process->m_shared_page_vaddr,
|
||||||
|
PageTable::UserSupervisor | PageTable::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
TRY(auxiliary_vector.push_back({
|
||||||
|
.a_type = LibELF::AT_SHARED_PAGE,
|
||||||
|
.a_un = { .a_ptr = reinterpret_cast<void*>(process->m_shared_page_vaddr) },
|
||||||
|
}));
|
||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
.a_type = LibELF::AT_NULL,
|
.a_type = LibELF::AT_NULL,
|
||||||
.a_un = { .a_val = 0 },
|
.a_un = { .a_val = 0 },
|
||||||
|
|
@ -683,6 +697,13 @@ namespace Kernel
|
||||||
for (auto& mapped_region : m_mapped_regions)
|
for (auto& mapped_region : m_mapped_regions)
|
||||||
MUST(mapped_regions.push_back(TRY(mapped_region->clone(*page_table))));
|
MUST(mapped_regions.push_back(TRY(mapped_region->clone(*page_table))));
|
||||||
|
|
||||||
|
const vaddr_t shared_page_vaddr = m_shared_page_vaddr;
|
||||||
|
page_table->map_page_at(
|
||||||
|
Processor::shared_page_paddr(),
|
||||||
|
shared_page_vaddr,
|
||||||
|
PageTable::UserSupervisor | PageTable::Present
|
||||||
|
);
|
||||||
|
|
||||||
Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp);
|
Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp);
|
||||||
forked->m_controlling_terminal = m_controlling_terminal;
|
forked->m_controlling_terminal = m_controlling_terminal;
|
||||||
forked->m_working_directory = BAN::move(working_directory);
|
forked->m_working_directory = BAN::move(working_directory);
|
||||||
|
|
@ -691,6 +712,7 @@ namespace Kernel
|
||||||
forked->m_environ = BAN::move(environ);
|
forked->m_environ = BAN::move(environ);
|
||||||
forked->m_executable = BAN::move(executable);
|
forked->m_executable = BAN::move(executable);
|
||||||
forked->m_page_table = BAN::move(page_table);
|
forked->m_page_table = BAN::move(page_table);
|
||||||
|
forked->m_shared_page_vaddr = BAN::move(shared_page_vaddr);
|
||||||
forked->m_open_file_descriptors = BAN::move(*open_file_descriptors);
|
forked->m_open_file_descriptors = BAN::move(*open_file_descriptors);
|
||||||
forked->m_mapped_regions = BAN::move(mapped_regions);
|
forked->m_mapped_regions = BAN::move(mapped_regions);
|
||||||
forked->m_has_called_exec = false;
|
forked->m_has_called_exec = false;
|
||||||
|
|
@ -766,6 +788,20 @@ namespace Kernel
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const vaddr_t shared_page_vaddr = new_page_table->reserve_free_page(new_mapped_regions.back()->vaddr(), USERSPACE_END);
|
||||||
|
if (shared_page_vaddr == 0)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
new_page_table->map_page_at(
|
||||||
|
Processor::shared_page_paddr(),
|
||||||
|
shared_page_vaddr,
|
||||||
|
PageTable::UserSupervisor | PageTable::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
TRY(auxiliary_vector.push_back({
|
||||||
|
.a_type = LibELF::AT_SHARED_PAGE,
|
||||||
|
.a_un = { .a_ptr = reinterpret_cast<void*>(shared_page_vaddr) },
|
||||||
|
}));
|
||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
.a_type = LibELF::AT_NULL,
|
.a_type = LibELF::AT_NULL,
|
||||||
.a_un = { .a_val = 0 },
|
.a_un = { .a_val = 0 },
|
||||||
|
|
@ -837,6 +873,9 @@ namespace Kernel
|
||||||
m_mapped_regions = BAN::move(new_mapped_regions);
|
m_mapped_regions = BAN::move(new_mapped_regions);
|
||||||
m_page_table = BAN::move(new_page_table);
|
m_page_table = BAN::move(new_page_table);
|
||||||
|
|
||||||
|
m_shared_page_vaddr = shared_page_vaddr;
|
||||||
|
m_threads.front()->update_processor_index_address();
|
||||||
|
|
||||||
execfd_guard.disable();
|
execfd_guard.disable();
|
||||||
|
|
||||||
m_cmdline = BAN::move(str_argv);
|
m_cmdline = BAN::move(str_argv);
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,19 @@ namespace Kernel
|
||||||
static constexpr uint32_t MSR_IA32_FS_BASE = 0xC0000100;
|
static constexpr uint32_t MSR_IA32_FS_BASE = 0xC0000100;
|
||||||
static constexpr uint32_t MSR_IA32_GS_BASE = 0xC0000101;
|
static constexpr uint32_t MSR_IA32_GS_BASE = 0xC0000101;
|
||||||
static constexpr uint32_t MSR_IA32_KERNEL_GS_BASE = 0xC0000102;
|
static constexpr uint32_t MSR_IA32_KERNEL_GS_BASE = 0xC0000102;
|
||||||
|
|
||||||
|
static constexpr uint32_t MSR_IA32_EFER = 0xC0000080;
|
||||||
|
static constexpr uint32_t MSR_IA32_STAR = 0xC0000081;
|
||||||
|
static constexpr uint32_t MSR_IA32_LSTAR = 0xC0000082;
|
||||||
|
static constexpr uint32_t MSR_IA32_FMASK = 0xC0000084;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ProcessorID Processor::s_bsp_id { PROCESSOR_NONE };
|
ProcessorID Processor::s_bsp_id { PROCESSOR_NONE };
|
||||||
BAN::Atomic<uint8_t> Processor::s_processor_count { 0 };
|
BAN::Atomic<uint8_t> Processor::s_processor_count { 0 };
|
||||||
BAN::Atomic<bool> Processor::s_is_smp_enabled { false };
|
BAN::Atomic<bool> Processor::s_is_smp_enabled { false };
|
||||||
BAN::Atomic<bool> Processor::s_should_print_cpu_load { false };
|
BAN::Atomic<bool> Processor::s_should_print_cpu_load { false };
|
||||||
|
paddr_t Processor::s_shared_page_paddr { 0 };
|
||||||
|
vaddr_t Processor::s_shared_page_vaddr { 0 };
|
||||||
|
|
||||||
static BAN::Atomic<uint8_t> s_processors_created { 0 };
|
static BAN::Atomic<uint8_t> s_processors_created { 0 };
|
||||||
|
|
||||||
|
|
@ -28,6 +35,8 @@ namespace Kernel
|
||||||
static BAN::Array<Processor, 0xFF> s_processors;
|
static BAN::Array<Processor, 0xFF> s_processors;
|
||||||
static BAN::Array<ProcessorID, 0xFF> s_processor_ids { PROCESSOR_NONE };
|
static BAN::Array<ProcessorID, 0xFF> s_processor_ids { PROCESSOR_NONE };
|
||||||
|
|
||||||
|
extern "C" void asm_syscall_handler();
|
||||||
|
|
||||||
ProcessorID Processor::read_processor_id()
|
ProcessorID Processor::read_processor_id()
|
||||||
{
|
{
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|
@ -85,13 +94,53 @@ namespace Kernel
|
||||||
|
|
||||||
// initialize GS
|
// initialize GS
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
// set gs base to pointer to this processor
|
{
|
||||||
uint64_t ptr = reinterpret_cast<uint64_t>(&processor);
|
// set gs base to pointer to this processor
|
||||||
uint32_t ptr_hi = ptr >> 32;
|
const uint64_t val = reinterpret_cast<uint64_t>(&processor);
|
||||||
uint32_t ptr_lo = ptr & 0xFFFFFFFF;
|
const uint32_t val_hi = val >> 32;
|
||||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_GS_BASE));
|
const uint32_t val_lo = val & 0xFFFFFFFF;
|
||||||
|
asm volatile("wrmsr" :: "d"(val_hi), "a"(val_lo), "c"(MSR_IA32_GS_BASE));
|
||||||
|
}
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
asm volatile("movw $0x28, %%ax; movw %%ax, %%gs" ::: "ax");
|
asm volatile("movw %0, %%gs" :: "r"(0x28));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
// enable syscall instruction
|
||||||
|
asm volatile("rdmsr; orb $1, %%al; wrmsr" :: "c"(MSR_IA32_EFER) : "eax", "edx");
|
||||||
|
|
||||||
|
{
|
||||||
|
union STAR
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t : 32;
|
||||||
|
uint16_t sel_ring0;
|
||||||
|
uint16_t sel_ring3;
|
||||||
|
};
|
||||||
|
uint64_t raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
// set kernel and user segments
|
||||||
|
const uint64_t val = STAR { .sel_ring0 = 0x08, .sel_ring3 = 0x18 | 3 }.raw;
|
||||||
|
const uint32_t val_hi = val >> 32;
|
||||||
|
const uint32_t val_lo = val & 0xFFFFFFFF;
|
||||||
|
asm volatile("wrmsr" :: "d"(val_hi), "a"(val_lo), "c"(MSR_IA32_STAR));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// set syscall handler address
|
||||||
|
const uint64_t val = reinterpret_cast<uint64_t>(&asm_syscall_handler);
|
||||||
|
const uint32_t val_hi = val >> 32;
|
||||||
|
const uint32_t val_lo = val & 0xFFFFFFFF;
|
||||||
|
asm volatile("wrmsr" :: "d"(val_hi), "a"(val_lo), "c"(MSR_IA32_LSTAR));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// mask DF and IF
|
||||||
|
const uint64_t val = (1 << 10) | (1 << 9);
|
||||||
|
const uint32_t val_hi = val >> 32;
|
||||||
|
const uint32_t val_lo = val & 0xFFFFFFFF;
|
||||||
|
asm volatile("wrmsr" :: "d"(val_hi), "a"(val_lo), "c"(MSR_IA32_FMASK));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ASSERT(processor.m_idt);
|
ASSERT(processor.m_idt);
|
||||||
|
|
@ -128,6 +177,33 @@ namespace Kernel
|
||||||
processor.m_smp_free = smp_storage;
|
processor.m_smp_free = smp_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Processor::initialize_shared_page()
|
||||||
|
{
|
||||||
|
[[maybe_unused]] constexpr size_t max_processors = (PAGE_SIZE - sizeof(API::SharedPage)) / sizeof(decltype(*API::SharedPage::cpus));
|
||||||
|
ASSERT(s_processors_created < max_processors);
|
||||||
|
|
||||||
|
s_shared_page_paddr = Heap::get().take_free_page();
|
||||||
|
ASSERT(s_shared_page_paddr);
|
||||||
|
|
||||||
|
s_shared_page_vaddr = PageTable::kernel().reserve_free_page(KERNEL_OFFSET);
|
||||||
|
ASSERT(s_shared_page_vaddr);
|
||||||
|
|
||||||
|
PageTable::kernel().map_page_at(
|
||||||
|
s_shared_page_paddr,
|
||||||
|
s_shared_page_vaddr,
|
||||||
|
PageTable::ReadWrite | PageTable::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
memset(reinterpret_cast<void*>(s_shared_page_vaddr), 0, PAGE_SIZE);
|
||||||
|
|
||||||
|
auto& shared_page = *reinterpret_cast<volatile API::SharedPage*>(s_shared_page_vaddr);
|
||||||
|
for (size_t i = 0; i <= 0xFF; i++)
|
||||||
|
shared_page.__sequence[i] = i;
|
||||||
|
shared_page.features = 0;
|
||||||
|
|
||||||
|
ASSERT(Processor::count() + sizeof(Kernel::API::SharedPage) <= PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
ProcessorID Processor::id_from_index(size_t index)
|
ProcessorID Processor::id_from_index(size_t index)
|
||||||
{
|
{
|
||||||
ASSERT(index < s_processor_count);
|
ASSERT(index < s_processor_count);
|
||||||
|
|
@ -142,8 +218,11 @@ namespace Kernel
|
||||||
// wait until bsp is ready
|
// wait until bsp is ready
|
||||||
if (current_is_bsp())
|
if (current_is_bsp())
|
||||||
{
|
{
|
||||||
|
initialize_shared_page();
|
||||||
|
|
||||||
s_processor_count = 1;
|
s_processor_count = 1;
|
||||||
s_processor_ids[0] = current_id();
|
s_processor_ids[0] = current_id();
|
||||||
|
s_processors[current_id().as_u32()].m_index = 0;
|
||||||
|
|
||||||
// single processor system
|
// single processor system
|
||||||
if (s_processors_created == 1)
|
if (s_processors_created == 1)
|
||||||
|
|
@ -167,9 +246,10 @@ namespace Kernel
|
||||||
while (s_processor_count == 0)
|
while (s_processor_count == 0)
|
||||||
__builtin_ia32_pause();
|
__builtin_ia32_pause();
|
||||||
|
|
||||||
auto lookup_index = s_processor_count++;
|
const auto index = s_processor_count++;
|
||||||
ASSERT(s_processor_ids[lookup_index] == PROCESSOR_NONE);
|
ASSERT(s_processor_ids[index] == PROCESSOR_NONE);
|
||||||
s_processor_ids[lookup_index] = current_id();
|
s_processor_ids[index] = current_id();
|
||||||
|
s_processors[current_id().as_u32()].m_index = index;
|
||||||
|
|
||||||
uint32_t expected = static_cast<uint32_t>(-1);
|
uint32_t expected = static_cast<uint32_t>(-1);
|
||||||
s_first_ap_ready_ms.compare_exchange(expected, SystemTimer::get().ms_since_boot());
|
s_first_ap_ready_ms.compare_exchange(expected, SystemTimer::get().ms_since_boot());
|
||||||
|
|
@ -191,6 +271,62 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Processor::initialize_tsc(uint8_t shift, uint64_t mult, uint64_t realtime_seconds)
|
||||||
|
{
|
||||||
|
auto& shared_page = Processor::shared_page();
|
||||||
|
|
||||||
|
shared_page.gettime_shared.shift = shift;
|
||||||
|
shared_page.gettime_shared.mult = mult;
|
||||||
|
shared_page.gettime_shared.realtime_seconds = realtime_seconds;
|
||||||
|
|
||||||
|
update_tsc();
|
||||||
|
|
||||||
|
broadcast_smp_message({
|
||||||
|
.type = SMPMessage::Type::UpdateTSC,
|
||||||
|
.dummy = 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
bool everyone_initialized { false };
|
||||||
|
while (!everyone_initialized)
|
||||||
|
{
|
||||||
|
everyone_initialized = true;
|
||||||
|
for (size_t i = 0; i < count(); i++)
|
||||||
|
{
|
||||||
|
if (shared_page.cpus[i].gettime_local.seq != 0)
|
||||||
|
continue;
|
||||||
|
everyone_initialized = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_page.features |= API::SPF_GETTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Processor::update_tsc()
|
||||||
|
{
|
||||||
|
auto& sgettime = shared_page().cpus[current_index()].gettime_local;
|
||||||
|
sgettime.seq = sgettime.seq + 1;
|
||||||
|
sgettime.last_ns = SystemTimer::get().ns_since_boot_no_tsc();
|
||||||
|
sgettime.last_tsc = __builtin_ia32_rdtsc();
|
||||||
|
sgettime.seq = sgettime.seq + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Processor::ns_since_boot_tsc()
|
||||||
|
{
|
||||||
|
const auto& shared_page = Processor::shared_page();
|
||||||
|
const auto& sgettime = shared_page.gettime_shared;
|
||||||
|
const auto& lgettime = shared_page.cpus[current_index()].gettime_local;
|
||||||
|
|
||||||
|
auto state = get_interrupt_state();
|
||||||
|
set_interrupt_state(InterruptState::Disabled);
|
||||||
|
|
||||||
|
const auto current_ns = lgettime.last_ns + (((__builtin_ia32_rdtsc() - lgettime.last_tsc) * sgettime.mult) >> sgettime.shift);
|
||||||
|
|
||||||
|
set_interrupt_state(state);
|
||||||
|
|
||||||
|
return current_ns;
|
||||||
|
}
|
||||||
|
|
||||||
void Processor::handle_ipi()
|
void Processor::handle_ipi()
|
||||||
{
|
{
|
||||||
handle_smp_messages();
|
handle_smp_messages();
|
||||||
|
|
@ -240,6 +376,9 @@ namespace Kernel
|
||||||
case SMPMessage::Type::UnblockThread:
|
case SMPMessage::Type::UnblockThread:
|
||||||
processor.m_scheduler->unblock_thread(message->unblock_thread);
|
processor.m_scheduler->unblock_thread(message->unblock_thread);
|
||||||
break;
|
break;
|
||||||
|
case SMPMessage::Type::UpdateTSC:
|
||||||
|
update_tsc();
|
||||||
|
break;
|
||||||
#if WITH_PROFILING
|
#if WITH_PROFILING
|
||||||
case SMPMessage::Type::StartProfiling:
|
case SMPMessage::Type::StartProfiling:
|
||||||
processor.start_profiling();
|
processor.start_profiling();
|
||||||
|
|
@ -266,36 +405,17 @@ namespace Kernel
|
||||||
|
|
||||||
void Processor::load_segments()
|
void Processor::load_segments()
|
||||||
{
|
{
|
||||||
{
|
load_fsbase();
|
||||||
const auto addr = scheduler().current_thread().get_fsbase();
|
load_gsbase();
|
||||||
#if ARCH(x86_64)
|
|
||||||
uint32_t ptr_hi = addr >> 32;
|
|
||||||
uint32_t ptr_lo = addr & 0xFFFFFFFF;
|
|
||||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_FS_BASE));
|
|
||||||
#elif ARCH(i686)
|
|
||||||
gdt().set_fsbase(addr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto addr = scheduler().current_thread().get_gsbase();
|
|
||||||
#if ARCH(x86_64)
|
|
||||||
uint32_t ptr_hi = addr >> 32;
|
|
||||||
uint32_t ptr_lo = addr & 0xFFFFFFFF;
|
|
||||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
|
|
||||||
#elif ARCH(i686)
|
|
||||||
gdt().set_gsbase(addr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Processor::load_fsbase()
|
void Processor::load_fsbase()
|
||||||
{
|
{
|
||||||
const auto addr = scheduler().current_thread().get_fsbase();
|
const auto addr = scheduler().current_thread().get_fsbase();
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
uint32_t ptr_hi = addr >> 32;
|
const uint32_t addr_hi = addr >> 32;
|
||||||
uint32_t ptr_lo = addr & 0xFFFFFFFF;
|
const uint32_t addr_lo = addr & 0xFFFFFFFF;
|
||||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_FS_BASE));
|
asm volatile("wrmsr" :: "d"(addr_hi), "a"(addr_lo), "c"(MSR_IA32_FS_BASE));
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
gdt().set_fsbase(addr);
|
gdt().set_fsbase(addr);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -305,9 +425,9 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
const auto addr = scheduler().current_thread().get_gsbase();
|
const auto addr = scheduler().current_thread().get_gsbase();
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
uint32_t ptr_hi = addr >> 32;
|
const uint32_t addr_hi = addr >> 32;
|
||||||
uint32_t ptr_lo = addr & 0xFFFFFFFF;
|
const uint32_t addr_lo = addr & 0xFFFFFFFF;
|
||||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
|
asm volatile("wrmsr" :: "d"(addr_hi), "a"(addr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
gdt().set_gsbase(addr);
|
gdt().set_gsbase(addr);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -375,13 +495,14 @@ namespace Kernel
|
||||||
if (!is_smp_enabled())
|
if (!is_smp_enabled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto state = get_interrupt_state();
|
const auto state = get_interrupt_state();
|
||||||
set_interrupt_state(InterruptState::Disabled);
|
set_interrupt_state(InterruptState::Disabled);
|
||||||
|
|
||||||
|
const auto current_id = Processor::current_id();
|
||||||
for (size_t i = 0; i < Processor::count(); i++)
|
for (size_t i = 0; i < Processor::count(); i++)
|
||||||
{
|
{
|
||||||
auto processor_id = s_processor_ids[i];
|
const auto processor_id = s_processor_ids[i];
|
||||||
if (processor_id != current_id())
|
if (processor_id != current_id)
|
||||||
send_smp_message(processor_id, message, false);
|
send_smp_message(processor_id, message, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -284,9 +284,14 @@ namespace Kernel
|
||||||
thread->set_cpu_time_start();
|
thread->set_cpu_time_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
Processor::gdt().set_tss_stack(thread->kernel_stack_top());
|
|
||||||
if (thread->is_userspace())
|
if (thread->is_userspace())
|
||||||
|
{
|
||||||
|
const vaddr_t kernel_stack_top = thread->kernel_stack_top();
|
||||||
|
Processor::gdt().set_tss_stack(kernel_stack_top);
|
||||||
|
Processor::set_thread_syscall_stack(kernel_stack_top);
|
||||||
Processor::load_segments();
|
Processor::load_segments();
|
||||||
|
}
|
||||||
|
|
||||||
*interrupt_stack = thread->interrupt_stack();
|
*interrupt_stack = thread->interrupt_stack();
|
||||||
*interrupt_registers = thread->interrupt_registers();
|
*interrupt_registers = thread->interrupt_registers();
|
||||||
|
|
||||||
|
|
@ -387,6 +392,9 @@ namespace Kernel
|
||||||
else
|
else
|
||||||
m_block_queue.add_thread_with_wake_time(node);
|
m_block_queue.add_thread_with_wake_time(node);
|
||||||
|
|
||||||
|
if (auto* thread = node->thread; thread->is_userspace() && thread->has_process())
|
||||||
|
thread->update_processor_index_address();
|
||||||
|
|
||||||
m_thread_count++;
|
m_thread_count++;
|
||||||
|
|
||||||
Processor::set_interrupt_state(state);
|
Processor::set_interrupt_state(state);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#include <BAN/Bitcast.h>
|
#include <BAN/Bitcast.h>
|
||||||
|
#include <kernel/API/Syscall.h>
|
||||||
#include <kernel/Debug.h>
|
#include <kernel/Debug.h>
|
||||||
#include <kernel/InterruptStack.h>
|
#include <kernel/InterruptStack.h>
|
||||||
#include <kernel/Process.h>
|
#include <kernel/Process.h>
|
||||||
#include <kernel/Scheduler.h>
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Syscall.h>
|
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
|
@ -40,10 +40,8 @@ namespace Kernel
|
||||||
|
|
||||||
static bool is_restartable_syscall(int syscall);
|
static bool is_restartable_syscall(int syscall);
|
||||||
|
|
||||||
extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, InterruptStack* interrupt_stack)
|
extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)
|
||||||
{
|
{
|
||||||
ASSERT(GDT::is_user_segment(interrupt_stack->cs));
|
|
||||||
|
|
||||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||||
|
|
||||||
Process::current().wait_while_stopped();
|
Process::current().wait_while_stopped();
|
||||||
|
|
|
||||||
|
|
@ -295,6 +295,20 @@ namespace Kernel
|
||||||
m_cpu_time_start_ns = UINT64_MAX;
|
m_cpu_time_start_ns = UINT64_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Thread::update_processor_index_address()
|
||||||
|
{
|
||||||
|
if (!is_userspace() || !has_process())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const vaddr_t vaddr = process().shared_page_vaddr() + Processor::current_index();
|
||||||
|
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
set_gsbase(vaddr);
|
||||||
|
#elif ARCH(i686)
|
||||||
|
set_fsbase(vaddr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<Thread*> Thread::pthread_create(entry_t entry, void* arg)
|
BAN::ErrorOr<Thread*> Thread::pthread_create(entry_t entry, void* arg)
|
||||||
{
|
{
|
||||||
auto* thread = TRY(create_userspace(m_process, m_process->page_table()));
|
auto* thread = TRY(create_userspace(m_process, m_process->page_table()));
|
||||||
|
|
@ -476,7 +490,11 @@ namespace Kernel
|
||||||
write_to_stack(cur_sp, 0x20 | 3);
|
write_to_stack(cur_sp, 0x20 | 3);
|
||||||
write_to_stack(cur_sp, sp);
|
write_to_stack(cur_sp, sp);
|
||||||
write_to_stack(cur_sp, 0x202);
|
write_to_stack(cur_sp, 0x202);
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
write_to_stack(cur_sp, 0x28 | 3);
|
||||||
|
#elif ARCH(i686)
|
||||||
write_to_stack(cur_sp, 0x18 | 3);
|
write_to_stack(cur_sp, 0x18 | 3);
|
||||||
|
#endif
|
||||||
write_to_stack(cur_sp, ip);
|
write_to_stack(cur_sp, ip);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -890,9 +908,9 @@ namespace Kernel
|
||||||
void Thread::save_sse()
|
void Thread::save_sse()
|
||||||
{
|
{
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
asm volatile("fxsave64 %0" :: "m"(m_sse_storage));
|
__builtin_ia32_fxsave64(m_sse_storage);
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
asm volatile("fxsave %0" :: "m"(m_sse_storage));
|
__builtin_ia32_fxsave(m_sse_storage);
|
||||||
#else
|
#else
|
||||||
#error
|
#error
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -901,9 +919,9 @@ namespace Kernel
|
||||||
void Thread::load_sse()
|
void Thread::load_sse()
|
||||||
{
|
{
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
asm volatile("fxrstor64 %0" :: "m"(m_sse_storage));
|
__builtin_ia32_fxrstor64(m_sse_storage);
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
asm volatile("fxrstor %0" :: "m"(m_sse_storage));
|
__builtin_ia32_fxrstor(m_sse_storage);
|
||||||
#else
|
#else
|
||||||
#error
|
#error
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -272,6 +272,8 @@ namespace Kernel
|
||||||
m_last_ticks = current_ticks;
|
m_last_ticks = current_ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SystemTimer::get().update_tsc();
|
||||||
|
|
||||||
if (should_invoke_scheduler())
|
if (should_invoke_scheduler())
|
||||||
Processor::scheduler().timer_interrupt();
|
Processor::scheduler().timer_interrupt();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ namespace Kernel
|
||||||
m_system_time_ms++;
|
m_system_time_ms++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SystemTimer::get().update_tsc();
|
||||||
|
|
||||||
if (should_invoke_scheduler())
|
if (should_invoke_scheduler())
|
||||||
Processor::scheduler().timer_interrupt();
|
Processor::scheduler().timer_interrupt();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
#include <BAN/Sort.h>
|
||||||
|
|
||||||
|
#include <kernel/CPUID.h>
|
||||||
#include <kernel/Scheduler.h>
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Timer/HPET.h>
|
#include <kernel/Timer/HPET.h>
|
||||||
#include <kernel/Timer/PIT.h>
|
#include <kernel/Timer/PIT.h>
|
||||||
|
|
@ -54,19 +57,100 @@ namespace Kernel
|
||||||
Kernel::panic("Could not initialize any timer");
|
Kernel::panic("Could not initialize any timer");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t SystemTimer::ms_since_boot() const
|
void SystemTimer::initialize_tsc()
|
||||||
{
|
{
|
||||||
return m_timer->ms_since_boot();
|
if (!CPUID::has_invariant_tsc())
|
||||||
|
{
|
||||||
|
dwarnln("CPU does not have an invariant TSC");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t tsc_freq = get_tsc_frequency();
|
||||||
|
|
||||||
|
dprintln("Initialized invariant TSC ({} Hz)", tsc_freq);
|
||||||
|
|
||||||
|
const uint8_t tsc_shift = 22;
|
||||||
|
const uint64_t tsc_mult = (static_cast<uint64_t>(1'000'000'000) << tsc_shift) / tsc_freq;
|
||||||
|
Processor::initialize_tsc(tsc_shift, tsc_mult, m_boot_time);
|
||||||
|
|
||||||
|
m_has_invariant_tsc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t SystemTimer::ns_since_boot() const
|
uint64_t SystemTimer::get_tsc_frequency() const
|
||||||
|
{
|
||||||
|
// take 5x 50 ms samples and use the median value
|
||||||
|
|
||||||
|
constexpr size_t tsc_sample_count = 5;
|
||||||
|
constexpr size_t tsc_sample_ns = 50'000'000;
|
||||||
|
|
||||||
|
uint64_t tsc_freq_samples[tsc_sample_count];
|
||||||
|
for (size_t i = 0; i < tsc_sample_count; i++)
|
||||||
|
{
|
||||||
|
const auto start_ns = m_timer->ns_since_boot();
|
||||||
|
|
||||||
|
const auto start_tsc = ({ __builtin_ia32_lfence(); __builtin_ia32_rdtsc(); });
|
||||||
|
while (m_timer->ns_since_boot() < start_ns + tsc_sample_ns)
|
||||||
|
Processor::pause();
|
||||||
|
const auto stop_tsc = ({ __builtin_ia32_lfence(); __builtin_ia32_rdtsc(); });
|
||||||
|
|
||||||
|
const auto stop_ns = m_timer->ns_since_boot();
|
||||||
|
|
||||||
|
const auto duration_ns = stop_ns - start_ns;
|
||||||
|
const auto count_tsc = stop_tsc - start_tsc;
|
||||||
|
|
||||||
|
tsc_freq_samples[i] = count_tsc * 1'000'000'000 / duration_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::sort::sort(tsc_freq_samples, tsc_freq_samples + tsc_sample_count);
|
||||||
|
|
||||||
|
return tsc_freq_samples[tsc_sample_count / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemTimer::update_tsc() const
|
||||||
|
{
|
||||||
|
if (!m_has_invariant_tsc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// only update every 100 ms
|
||||||
|
if (++m_timer_ticks < 100)
|
||||||
|
return;
|
||||||
|
m_timer_ticks = 0;
|
||||||
|
|
||||||
|
Processor::update_tsc();
|
||||||
|
Processor::broadcast_smp_message({
|
||||||
|
.type = Processor::SMPMessage::Type::UpdateTSC,
|
||||||
|
.dummy = 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SystemTimer::ns_since_boot_no_tsc() const
|
||||||
{
|
{
|
||||||
return m_timer->ns_since_boot();
|
return m_timer->ns_since_boot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t SystemTimer::ms_since_boot() const
|
||||||
|
{
|
||||||
|
if (!m_has_invariant_tsc)
|
||||||
|
return m_timer->ms_since_boot();
|
||||||
|
return Processor::ns_since_boot_tsc() / 1'000'000;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SystemTimer::ns_since_boot() const
|
||||||
|
{
|
||||||
|
if (!m_has_invariant_tsc)
|
||||||
|
return m_timer->ns_since_boot();
|
||||||
|
return Processor::ns_since_boot_tsc();
|
||||||
|
}
|
||||||
|
|
||||||
timespec SystemTimer::time_since_boot() const
|
timespec SystemTimer::time_since_boot() const
|
||||||
{
|
{
|
||||||
return m_timer->time_since_boot();
|
if (!m_has_invariant_tsc)
|
||||||
|
return m_timer->time_since_boot();
|
||||||
|
const auto ns_since_boot = Processor::ns_since_boot_tsc();
|
||||||
|
return {
|
||||||
|
.tv_sec = static_cast<time_t>(ns_since_boot / 1'000'000'000),
|
||||||
|
.tv_nsec = static_cast<long>(ns_since_boot % 1'000'000'000)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemTimer::pre_scheduler_sleep_needs_lock() const
|
bool SystemTimer::pre_scheduler_sleep_needs_lock() const
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
#include <kernel/Processor.h>
|
#include <kernel/Processor.h>
|
||||||
#include <kernel/Random.h>
|
#include <kernel/Random.h>
|
||||||
#include <kernel/Scheduler.h>
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Syscall.h>
|
|
||||||
#include <kernel/Terminal/FramebufferTerminal.h>
|
#include <kernel/Terminal/FramebufferTerminal.h>
|
||||||
#include <kernel/Terminal/Serial.h>
|
#include <kernel/Terminal/Serial.h>
|
||||||
#include <kernel/Terminal/VirtualTTY.h>
|
#include <kernel/Terminal/VirtualTTY.h>
|
||||||
|
|
@ -208,6 +207,8 @@ static void init2(void*)
|
||||||
|
|
||||||
dprintln("Scheduler started");
|
dprintln("Scheduler started");
|
||||||
|
|
||||||
|
SystemTimer::get().initialize_tsc();
|
||||||
|
|
||||||
auto console = MUST(DevFileSystem::get().root_inode()->find_inode(cmdline.console));
|
auto console = MUST(DevFileSystem::get().root_inode()->find_inode(cmdline.console));
|
||||||
ASSERT(console->is_tty());
|
ASSERT(console->is_tty());
|
||||||
static_cast<Kernel::TTY*>(console.ptr())->set_as_current();
|
static_cast<Kernel::TTY*>(console.ptr())->set_as_current();
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#!/bin/bash ../install.sh
|
#!/bin/bash ../install.sh
|
||||||
|
|
||||||
NAME='freetype'
|
NAME='freetype'
|
||||||
VERSION='2.13.3'
|
VERSION='2.14.1'
|
||||||
DOWNLOAD_URL="https://download.savannah.gnu.org/releases/freetype/freetype-$VERSION.tar.gz#5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747"
|
DOWNLOAD_URL="https://download.savannah.gnu.org/releases/freetype/freetype-$VERSION.tar.xz#32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc"
|
||||||
DEPENDENCIES=('zlib' 'libpng')
|
DEPENDENCIES=('zlib' 'libpng')
|
||||||
CONFIG_SUB=('builds/unix/config.sub')
|
CONFIG_SUB=('builds/unix/config.sub')
|
||||||
CONFIGURE_OPTIONS=(
|
CONFIGURE_OPTIONS=(
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,11 @@
|
||||||
NAME='openal-soft'
|
NAME='openal-soft'
|
||||||
VERSION='1.24.3'
|
VERSION='1.24.3'
|
||||||
DOWNLOAD_URL="https://github.com/kcat/openal-soft/archive/refs/tags/$VERSION.tar.gz#7e1fecdeb45e7f78722b776c5cf30bd33934b961d7fd2a11e0494e064cc631ce"
|
DOWNLOAD_URL="https://github.com/kcat/openal-soft/archive/refs/tags/$VERSION.tar.gz#7e1fecdeb45e7f78722b776c5cf30bd33934b961d7fd2a11e0494e064cc631ce"
|
||||||
DEPENDENCIES=('zlib' 'libsndfile')
|
DEPENDENCIES=('SDL2' 'zlib' 'libsndfile')
|
||||||
|
|
||||||
configure() {
|
configure() {
|
||||||
$BANAN_CMAKE \
|
$BANAN_CMAKE -B build -S . -G Ninja --fresh \
|
||||||
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
|
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
|
||||||
-B build -G Ninja --fresh . \
|
|
||||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
-DALSOFT_EXAMPLES=OFF \
|
-DALSOFT_EXAMPLES=OFF \
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#!/bin/bash ../install.sh
|
#!/bin/bash ../install.sh
|
||||||
|
|
||||||
NAME='openssl'
|
NAME='openssl'
|
||||||
VERSION='3.3.1'
|
VERSION='3.6.0'
|
||||||
DOWNLOAD_URL="https://github.com/openssl/openssl/releases/download/openssl-$VERSION/openssl-$VERSION.tar.gz#777cd596284c883375a2a7a11bf5d2786fc5413255efab20c50d6ffe6d020b7e"
|
DOWNLOAD_URL="https://github.com/openssl/openssl/releases/download/openssl-$VERSION/openssl-$VERSION.tar.gz#b6a5f44b7eb69e3fa35dbf15524405b44837a481d43d81daddde3ff21fcbb8e9"
|
||||||
DEPENDENCIES=('zlib')
|
DEPENDENCIES=('zlib')
|
||||||
MAKE_INSTALL_TARGETS=('install_sw' 'install_ssldirs')
|
MAKE_INSTALL_TARGETS=('install_sw' 'install_ssldirs')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
diff -ruN openssl-3.3.1/crypto/bio/bss_dgram.c openssl-3.3.1-banan_os/crypto/bio/bss_dgram.c
|
|
||||||
--- openssl-3.3.1/crypto/bio/bss_dgram.c 2024-06-04 15:53:04.000000000 +0300
|
|
||||||
+++ openssl-3.3.1-banan_os/crypto/bio/bss_dgram.c 2025-06-01 19:48:55.088806701 +0300
|
|
||||||
@@ -61,7 +61,7 @@
|
|
||||||
# define NO_RECVMMSG
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
-# if defined(__GNU__)
|
|
||||||
+# if defined(__GNU__) || defined(__banan_os__)
|
|
||||||
/* GNU/Hurd does not have IP_PKTINFO yet */
|
|
||||||
#undef NO_RECVMSG
|
|
||||||
#define NO_RECVMSG
|
|
||||||
|
|
@ -34,10 +34,16 @@ NET_ARGS="-device e1000e,netdev=net $NET_ARGS"
|
||||||
|
|
||||||
USB_ARGS='-device qemu-xhci -device usb-kbd,port=1 -device usb-hub,port=2 -device usb-tablet,port=2.1'
|
USB_ARGS='-device qemu-xhci -device usb-kbd,port=1 -device usb-hub,port=2 -device usb-tablet,port=2.1'
|
||||||
|
|
||||||
SOUND_ARGS='-device ac97'
|
#SOUND_ARGS='-device ac97'
|
||||||
|
SOUND_ARGS='-device intel-hda -device hda-output'
|
||||||
|
|
||||||
|
if [[ $@ == *"-accel kvm"* ]]; then
|
||||||
|
CPU_ARGS='-cpu host,migratable=off'
|
||||||
|
fi
|
||||||
|
|
||||||
qemu-system-$QEMU_ARCH \
|
qemu-system-$QEMU_ARCH \
|
||||||
-m 1G -smp 4 \
|
-m 1G -smp 4 \
|
||||||
|
$CPU_ARGS \
|
||||||
$BIOS_ARGS \
|
$BIOS_ARGS \
|
||||||
$USB_ARGS \
|
$USB_ARGS \
|
||||||
$DISK_ARGS \
|
$DISK_ARGS \
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
#include <BAN/Debug.h>
|
#include <BAN/Debug.h>
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
|
|
||||||
|
#include <kernel/API/SharedPage.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <langinfo.h>
|
#include <langinfo.h>
|
||||||
|
|
@ -15,9 +17,53 @@ int daylight;
|
||||||
long timezone;
|
long timezone;
|
||||||
char* tzname[2];
|
char* tzname[2];
|
||||||
|
|
||||||
|
extern volatile Kernel::API::SharedPage* g_shared_page;
|
||||||
|
|
||||||
int clock_gettime(clockid_t clock_id, struct timespec* tp)
|
int clock_gettime(clockid_t clock_id, struct timespec* tp)
|
||||||
{
|
{
|
||||||
return syscall(SYS_CLOCK_GETTIME, clock_id, tp);
|
if (clock_id != CLOCK_MONOTONIC && clock_id != CLOCK_REALTIME)
|
||||||
|
return syscall(SYS_CLOCK_GETTIME, clock_id, tp);
|
||||||
|
|
||||||
|
if (g_shared_page == nullptr || !(g_shared_page->features & Kernel::API::SPF_GETTIME))
|
||||||
|
return syscall(SYS_CLOCK_GETTIME, clock_id, tp);
|
||||||
|
|
||||||
|
const auto get_cpu =
|
||||||
|
[]() -> uint8_t {
|
||||||
|
uint8_t cpu;
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
asm volatile("movb %%gs:0, %0" : "=r"(cpu));
|
||||||
|
#elif defined(__i686__)
|
||||||
|
asm volatile("movb %%fs:0, %0" : "=q"(cpu));
|
||||||
|
#endif
|
||||||
|
return cpu;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const auto cpu = get_cpu();
|
||||||
|
|
||||||
|
const auto& sgettime = g_shared_page->gettime_shared;
|
||||||
|
const auto& lgettime = g_shared_page->cpus[cpu].gettime_local;
|
||||||
|
|
||||||
|
const auto old_seq = lgettime.seq;
|
||||||
|
if (old_seq & 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto monotonic_ns = lgettime.last_ns + (((__builtin_ia32_rdtsc() - lgettime.last_tsc) * sgettime.mult) >> sgettime.shift);
|
||||||
|
|
||||||
|
if (old_seq != lgettime.seq || cpu != get_cpu())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
*tp = {
|
||||||
|
.tv_sec = static_cast<time_t>(monotonic_ns / 1'000'000'000),
|
||||||
|
.tv_nsec = static_cast<long>(monotonic_ns % 1'000'000'000)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (clock_id == CLOCK_REALTIME)
|
||||||
|
tp->tv_sec += sgettime.realtime_seconds;
|
||||||
|
|
||||||
|
return monotonic_ns;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int clock_getres(clockid_t clock_id, struct timespec* res)
|
int clock_getres(clockid_t clock_id, struct timespec* res)
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@
|
||||||
#include <BAN/Debug.h>
|
#include <BAN/Debug.h>
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/StringView.h>
|
||||||
|
|
||||||
|
#include <LibELF/AuxiliaryVector.h>
|
||||||
|
|
||||||
|
#include <kernel/API/SharedPage.h>
|
||||||
|
#include <kernel/API/Syscall.h>
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
#include <kernel/Syscall.h>
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
@ -31,6 +34,8 @@ struct init_funcs_t
|
||||||
|
|
||||||
extern "C" char** environ;
|
extern "C" char** environ;
|
||||||
|
|
||||||
|
volatile Kernel::API::SharedPage* g_shared_page = nullptr;
|
||||||
|
|
||||||
#define DUMP_BACKTRACE 1
|
#define DUMP_BACKTRACE 1
|
||||||
#define DEMANGLE_BACKTRACE 0
|
#define DEMANGLE_BACKTRACE 0
|
||||||
|
|
||||||
|
|
@ -40,11 +45,28 @@ extern "C" char** environ;
|
||||||
|
|
||||||
static void __dump_backtrace(int, siginfo_t*, void*);
|
static void __dump_backtrace(int, siginfo_t*, void*);
|
||||||
|
|
||||||
|
static LibELF::AuxiliaryVector* find_auxv(char** envp)
|
||||||
|
{
|
||||||
|
if (envp == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
char** null_env = envp;
|
||||||
|
while (*null_env)
|
||||||
|
null_env++;
|
||||||
|
|
||||||
|
return reinterpret_cast<LibELF::AuxiliaryVector*>(null_env + 1);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t fini_funcs)
|
extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t fini_funcs)
|
||||||
{
|
{
|
||||||
if (::environ == nullptr)
|
if (::environ == nullptr)
|
||||||
::environ = environ;
|
::environ = environ;
|
||||||
|
|
||||||
|
if (auto* auxv = find_auxv(environ))
|
||||||
|
for (auto* aux = auxv; aux->a_type != LibELF::AT_NULL; aux++)
|
||||||
|
if (aux->a_type == LibELF::AT_SHARED_PAGE)
|
||||||
|
g_shared_page = static_cast<Kernel::API::SharedPage*>(aux->a_un.a_ptr);
|
||||||
|
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
if (uthread* self = reinterpret_cast<uthread*>(syscall(SYS_GET_FSBASE)))
|
if (uthread* self = reinterpret_cast<uthread*>(syscall(SYS_GET_FSBASE)))
|
||||||
#elif defined(__i686__)
|
#elif defined(__i686__)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ namespace LibELF
|
||||||
AT_PHDR = 3,
|
AT_PHDR = 3,
|
||||||
AT_PHENT = 4,
|
AT_PHENT = 4,
|
||||||
AT_PHNUM = 5,
|
AT_PHNUM = 5,
|
||||||
|
|
||||||
|
AT_SHARED_PAGE = 0xFFFF0001,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
#include <kernel/Syscall.h>
|
#include <kernel/API/Syscall.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue