mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 13:36:13 +03:00
Kernel: Reorganize Arch/x86 directory to Arch/x86_64 after i686 removal
No functional change.
This commit is contained in:
parent
5ff318cf3a
commit
91db482ad3
Notes:
sideshowbarker
2024-07-17 08:42:05 +09:00
Author: https://github.com/supercomputer7 Commit: https://github.com/SerenityOS/serenity/commit/91db482ad3 Pull-request: https://github.com/SerenityOS/serenity/pull/15467 Issue: https://github.com/SerenityOS/serenity/issues/15444 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/Hendiadyoin1 Reviewed-by: https://github.com/fuel-pcbox
@ -17,7 +17,7 @@
|
||||
#define MSB(x) (((x) >> 8) & 0xFF)
|
||||
|
||||
#if ARCH(X86_64)
|
||||
# include <Kernel/Arch/x86/CPU.h>
|
||||
# include <Kernel/Arch/x86_64/CPU.h>
|
||||
#elif ARCH(AARCH64)
|
||||
# include <Kernel/Arch/aarch64/CPU.h>
|
||||
#else
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <AK/Platform.h>
|
||||
|
||||
#if ARCH(X86_64)
|
||||
# include <Kernel/Arch/x86/IRQController.h>
|
||||
# include <Kernel/Arch/x86_64/IRQController.h>
|
||||
#elif ARCH(AARCH64)
|
||||
# include <Kernel/Arch/aarch64/IRQController.h>
|
||||
#else
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <AK/Platform.h>
|
||||
|
||||
#if ARCH(X86_64)
|
||||
# include <Kernel/Arch/x86/InterruptManagement.h>
|
||||
# include <Kernel/Arch/x86_64/InterruptManagement.h>
|
||||
#elif ARCH(AARCH64)
|
||||
# include <Kernel/Arch/aarch64/InterruptManagement.h>
|
||||
#else
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <AK/Types.h>
|
||||
|
||||
#if ARCH(X86_64)
|
||||
# include <Kernel/Arch/x86/Interrupts.h>
|
||||
# include <Kernel/Arch/x86_64/Interrupts.h>
|
||||
#endif
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <AK/Platform.h>
|
||||
|
||||
#if ARCH(X86_64)
|
||||
# include <Kernel/Arch/x86/PageDirectory.h>
|
||||
# include <Kernel/Arch/x86_64/PageDirectory.h>
|
||||
#elif ARCH(AARCH64)
|
||||
# include <Kernel/Arch/aarch64/PageDirectory.h>
|
||||
#else
|
||||
|
@ -24,7 +24,7 @@ void restore_processor_interrupts_state(InterruptsState);
|
||||
}
|
||||
|
||||
#if ARCH(X86_64)
|
||||
# include <Kernel/Arch/x86/Processor.h>
|
||||
# include <Kernel/Arch/x86_64/Processor.h>
|
||||
#elif ARCH(AARCH64)
|
||||
# include <Kernel/Arch/aarch64/Processor.h>
|
||||
#else
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <AK/Platform.h>
|
||||
|
||||
#if ARCH(X86_64)
|
||||
# include <Kernel/Arch/x86/RegisterState.h>
|
||||
# include <Kernel/Arch/x86_64/RegisterState.h>
|
||||
#elif ARCH(AARCH64)
|
||||
# include <Kernel/Arch/aarch64/RegisterState.h>
|
||||
#else
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <AK/Platform.h>
|
||||
|
||||
#if ARCH(X86_64)
|
||||
# include <Kernel/Arch/x86/TrapFrame.h>
|
||||
# include <Kernel/Arch/x86_64/TrapFrame.h>
|
||||
#elif ARCH(AARCH64)
|
||||
# include <Kernel/Arch/aarch64/TrapFrame.h>
|
||||
#else
|
||||
|
@ -47,7 +47,7 @@ extern "C" void handle_interrupt(TrapFrame const* const)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Share the code below with Arch/x86/common/Interrupts.cpp
|
||||
// FIXME: Share the code below with Arch/x86_64/Interrupts.cpp
|
||||
// While refactoring, the interrupt handlers can also be moved into the InterruptManagement class.
|
||||
GenericInterruptHandler& get_interrupt_handler(u8 interrupt_number)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
# include <Kernel/Arch/x86/mcontext.h>
|
||||
# include <Kernel/Arch/x86_64/mcontext.h>
|
||||
#elif defined(__aarch64__)
|
||||
# include <Kernel/Arch/aarch64/mcontext.h>
|
||||
#endif
|
||||
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
#include <Kernel/Arch/Processor.h>
|
||||
#include <Kernel/Arch/x86/ASM_wrapper.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
#define XCR_XFEATURE_ENABLED_MASK 0
|
||||
|
||||
UNMAP_AFTER_INIT u64 read_xcr0()
|
||||
{
|
||||
u32 eax, edx;
|
||||
asm volatile("xgetbv"
|
||||
: "=a"(eax), "=d"(edx)
|
||||
: "c"(XCR_XFEATURE_ENABLED_MASK));
|
||||
return eax + ((u64)edx << 32);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void write_xcr0(u64 value)
|
||||
{
|
||||
u32 eax = value;
|
||||
u32 edx = value >> 32;
|
||||
asm volatile("xsetbv" ::"a"(eax), "d"(edx), "c"(XCR_XFEATURE_ENABLED_MASK));
|
||||
}
|
||||
|
||||
void stac()
|
||||
{
|
||||
if (!Processor::current().has_feature(CPUFeature::SMAP))
|
||||
return;
|
||||
asm volatile("stac" ::
|
||||
: "cc");
|
||||
}
|
||||
|
||||
void clac()
|
||||
{
|
||||
if (!Processor::current().has_feature(CPUFeature::SMAP))
|
||||
return;
|
||||
asm volatile("clac" ::
|
||||
: "cc");
|
||||
}
|
||||
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
#include <Kernel/Arch/x86/ASM_wrapper.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
UNMAP_AFTER_INIT void write_cr0(FlatPtr value)
|
||||
{
|
||||
asm volatile("mov %%eax, %%cr0" ::"a"(value));
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void write_cr4(FlatPtr value)
|
||||
{
|
||||
asm volatile("mov %%eax, %%cr4" ::"a"(value));
|
||||
}
|
||||
FlatPtr read_cr0()
|
||||
{
|
||||
FlatPtr cr0;
|
||||
asm("mov %%cr0, %%eax"
|
||||
: "=a"(cr0));
|
||||
return cr0;
|
||||
}
|
||||
|
||||
FlatPtr read_cr2()
|
||||
{
|
||||
FlatPtr cr2;
|
||||
asm("mov %%cr2, %%eax"
|
||||
: "=a"(cr2));
|
||||
return cr2;
|
||||
}
|
||||
|
||||
FlatPtr read_cr3()
|
||||
{
|
||||
FlatPtr cr3;
|
||||
asm("mov %%cr3, %%eax"
|
||||
: "=a"(cr3));
|
||||
return cr3;
|
||||
}
|
||||
|
||||
void write_cr3(FlatPtr cr3)
|
||||
{
|
||||
// NOTE: If you're here from a GPF crash, it's very likely that a PDPT entry is incorrect, not this!
|
||||
asm volatile("mov %%eax, %%cr3" ::"a"(cr3)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
FlatPtr read_cr4()
|
||||
{
|
||||
FlatPtr cr4;
|
||||
asm("mov %%cr4, %%eax"
|
||||
: "=a"(cr4));
|
||||
return cr4;
|
||||
}
|
||||
|
||||
#define DEFINE_DEBUG_REGISTER(index) \
|
||||
FlatPtr read_dr##index() \
|
||||
{ \
|
||||
FlatPtr value; \
|
||||
asm("mov %%dr" #index ", %%eax" \
|
||||
: "=a"(value)); \
|
||||
return value; \
|
||||
} \
|
||||
void write_dr##index(FlatPtr value) \
|
||||
{ \
|
||||
asm volatile("mov %%eax, %%dr" #index ::"a"(value)); \
|
||||
}
|
||||
|
||||
DEFINE_DEBUG_REGISTER(0);
|
||||
DEFINE_DEBUG_REGISTER(1);
|
||||
DEFINE_DEBUG_REGISTER(2);
|
||||
DEFINE_DEBUG_REGISTER(3);
|
||||
DEFINE_DEBUG_REGISTER(6);
|
||||
DEFINE_DEBUG_REGISTER(7);
|
||||
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
#include <Kernel/Sections.h>
|
||||
|
||||
.extern init_ap
|
||||
.type init_ap, @function
|
||||
|
||||
/*
|
||||
The apic_ap_start function will be loaded to P0x00008000 where the APIC
|
||||
will boot the AP from in real mode. This code also contains space for
|
||||
special variables that *must* remain here. When initializing the APIC,
|
||||
the code here gets copied to P0x00008000, the variables in here get
|
||||
populated and then the boot of the APs will be triggered.
|
||||
Having the variables here allows us to access them from real mode. Also, the
|
||||
code here avoids the need for relocation entries.
|
||||
|
||||
Basically, the variables between apic_ap_start and end_apic_ap_start
|
||||
*MUST* remain here and cannot be moved into a .bss or any other location.
|
||||
*/
|
||||
.global apic_ap_start
|
||||
.type apic_ap_start, @function
|
||||
apic_ap_start:
|
||||
.code16
|
||||
cli
|
||||
jmp $0x800, $(1f - apic_ap_start) /* avoid relocation entries */
|
||||
1:
|
||||
mov %cs, %ax
|
||||
mov %ax, %ds
|
||||
|
||||
xor %ax, %ax
|
||||
mov %ax, %sp
|
||||
|
||||
/* load the first temporary gdt */
|
||||
lgdt (ap_cpu_gdtr_initial - apic_ap_start)
|
||||
|
||||
/* enable PM */
|
||||
movl %cr0, %eax
|
||||
orl $1, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
ljmpl $8, $(apic_ap_start32 - apic_ap_start + 0x8000)
|
||||
apic_ap_start32:
|
||||
.code32
|
||||
mov $0x10, %ax
|
||||
mov %ax, %ss
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
|
||||
movl $0x8000, %ebp
|
||||
|
||||
/* generate a unique ap cpu id (0 means 1st ap, not bsp!) */
|
||||
xorl %eax, %eax
|
||||
incl %eax
|
||||
lock; xaddl %eax, (ap_cpu_id - apic_ap_start)(%ebp) /* avoid relocation entries */
|
||||
movl %eax, %esi
|
||||
|
||||
/* find our allocated stack based on the generated id */
|
||||
movl (ap_cpu_init_stacks - apic_ap_start)(%ebp, %eax, 4), %esp
|
||||
|
||||
/* check if we support NX and enable it if we do */
|
||||
movl $0x80000001, %eax
|
||||
cpuid
|
||||
testl $0x100000, %edx
|
||||
je (1f - apic_ap_start + 0x8000)
|
||||
/* turn on IA32_EFER.NXE */
|
||||
movl $0xc0000080, %ecx
|
||||
rdmsr
|
||||
orl $0x800, %eax
|
||||
wrmsr
|
||||
1:
|
||||
|
||||
/* load the bsp's cr3 value */
|
||||
movl (ap_cpu_init_cr3 - apic_ap_start)(%ebp), %eax
|
||||
movl %eax, %cr3
|
||||
|
||||
/* enable PAE + PSE */
|
||||
movl %cr4, %eax
|
||||
orl $0x60, %eax
|
||||
movl %eax, %cr4
|
||||
|
||||
/* enable PG */
|
||||
movl %cr0, %eax
|
||||
orl $0x80000000, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* load a second temporary gdt that points above 3GB */
|
||||
lgdt (ap_cpu_gdtr_initial2 - apic_ap_start + 0xc0008000)
|
||||
|
||||
/* jump above 3GB into our identity mapped area now */
|
||||
ljmp $8, $(apic_ap_start32_2 - apic_ap_start + 0xc0008000)
|
||||
apic_ap_start32_2:
|
||||
/* flush the TLB */
|
||||
movl %cr3, %eax
|
||||
movl %eax, %cr3
|
||||
|
||||
movl $0xc0008000, %ebp
|
||||
|
||||
/* now load the final gdt and idt from the identity mapped area */
|
||||
movl (ap_cpu_gdtr - apic_ap_start)(%ebp), %eax
|
||||
lgdt (%eax)
|
||||
movl (ap_cpu_idtr - apic_ap_start)(%ebp), %eax
|
||||
lidt (%eax)
|
||||
|
||||
/* set same cr0 and cr4 values as the BSP */
|
||||
movl (ap_cpu_init_cr0 - apic_ap_start)(%ebp), %eax
|
||||
movl %eax, %cr0
|
||||
movl (ap_cpu_init_cr4 - apic_ap_start)(%ebp), %eax
|
||||
movl %eax, %cr4
|
||||
|
||||
/* push the Processor pointer this CPU is going to use */
|
||||
movl (ap_cpu_init_processor_info_array - apic_ap_start)(%ebp), %eax
|
||||
addl kernel_mapping_base, %eax
|
||||
movl 0(%eax, %esi, 4), %eax
|
||||
push %eax
|
||||
|
||||
/* push the cpu id, 0 representing the bsp and call into c++ */
|
||||
incl %esi
|
||||
push %esi
|
||||
|
||||
xor %ebp, %ebp
|
||||
cld
|
||||
|
||||
/* We are in identity mapped P0x8000 and the BSP will unload this code
|
||||
once all APs are initialized, so call init_ap but return to our
|
||||
infinite loop */
|
||||
push $loop
|
||||
ljmp $8, $init_ap
|
||||
|
||||
loop:
|
||||
hlt
|
||||
jmp loop
|
||||
|
||||
.align 4
|
||||
.global apic_ap_start_size
|
||||
apic_ap_start_size:
|
||||
.2byte end_apic_ap_start - apic_ap_start
|
||||
.align 4
|
||||
ap_cpu_id:
|
||||
.4byte 0x0
|
||||
ap_cpu_gdt:
|
||||
/* null */
|
||||
.8byte 0x0
|
||||
/* code */
|
||||
.4byte 0x0000FFFF
|
||||
.4byte 0x00cf9a00
|
||||
/* data */
|
||||
.4byte 0x0000FFFF
|
||||
.4byte 0x00cf9200
|
||||
ap_cpu_gdt_end:
|
||||
ap_cpu_gdtr_initial:
|
||||
.2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
|
||||
.4byte (ap_cpu_gdt - apic_ap_start) + 0x8000
|
||||
ap_cpu_gdtr_initial2:
|
||||
.2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
|
||||
.4byte (ap_cpu_gdt - apic_ap_start) + 0xc0008000
|
||||
.global ap_cpu_gdtr
|
||||
ap_cpu_gdtr:
|
||||
.4byte 0x0 /* will be set at runtime */
|
||||
.global ap_cpu_idtr
|
||||
ap_cpu_idtr:
|
||||
.4byte 0x0 /* will be set at runtime */
|
||||
.global ap_cpu_init_cr0
|
||||
ap_cpu_init_cr0:
|
||||
.4byte 0x0 /* will be set at runtime */
|
||||
.global ap_cpu_init_cr3
|
||||
ap_cpu_init_cr3:
|
||||
.4byte 0x0 /* will be set at runtime */
|
||||
.global ap_cpu_init_cr4
|
||||
ap_cpu_init_cr4:
|
||||
.4byte 0x0 /* will be set at runtime */
|
||||
.global ap_cpu_init_processor_info_array
|
||||
ap_cpu_init_processor_info_array:
|
||||
.4byte 0x0 /* will be set at runtime */
|
||||
.global ap_cpu_init_stacks
|
||||
ap_cpu_init_stacks:
|
||||
/* array of allocated stack pointers */
|
||||
/* NOTE: ap_cpu_init_stacks must be the last variable before
|
||||
end_apic_ap_start! */
|
||||
.set end_apic_ap_start, .
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/TrapFrame.h>
|
||||
#include <Kernel/Arch/x86/DescriptorTable.h>
|
||||
|
||||
// clang-format off
|
||||
asm(
|
||||
".globl interrupt_common_asm_entry\n"
|
||||
"interrupt_common_asm_entry: \n"
|
||||
" pusha\n"
|
||||
" pushl %ds\n"
|
||||
" pushl %es\n"
|
||||
" pushl %fs\n"
|
||||
" pushl %gs\n"
|
||||
" pushl %ss\n"
|
||||
" mov $" __STRINGIFY(GDT_SELECTOR_DATA0) ", %ax\n"
|
||||
" mov %ax, %ds\n"
|
||||
" mov %ax, %es\n"
|
||||
" mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n"
|
||||
" mov %ax, %gs\n"
|
||||
" pushl %esp \n" // set TrapFrame::regs
|
||||
" subl $" __STRINGIFY(TRAP_FRAME_SIZE - 4) ", %esp \n"
|
||||
" movl %esp, %ebx \n" // save pointer to TrapFrame
|
||||
" pushl %ebx \n"
|
||||
" cld\n"
|
||||
" call enter_trap \n"
|
||||
" movl %ebx, 0(%esp) \n" // push pointer to TrapFrame
|
||||
" call handle_interrupt\n"
|
||||
" movl %ebx, 0(%esp) \n" // push pointer to TrapFrame
|
||||
".globl common_trap_exit \n"
|
||||
"common_trap_exit: \n"
|
||||
// another thread may have handled this trap at this point, so don't
|
||||
// make assumptions about the stack other than there's a TrapFrame
|
||||
// and a pointer to it.
|
||||
" call exit_trap \n"
|
||||
" addl $" __STRINGIFY(TRAP_FRAME_SIZE + 4) ", %esp\n" // pop TrapFrame and pointer to it
|
||||
".globl interrupt_common_asm_exit \n"
|
||||
"interrupt_common_asm_exit: \n"
|
||||
" addl $4, %esp\n" // pop %ss
|
||||
" popl %gs\n"
|
||||
" popl %fs\n"
|
||||
" popl %es\n"
|
||||
" popl %ds\n"
|
||||
" popa\n"
|
||||
" addl $0x4, %esp\n" // skip exception_code, isr_number
|
||||
" iret\n"
|
||||
);
|
||||
// clang-format on
|
@ -1,277 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <Kernel/Arch/Processor.h>
|
||||
#include <Kernel/Arch/TrapFrame.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/Random.h>
|
||||
#include <Kernel/Scheduler.h>
|
||||
#include <Kernel/Sections.h>
|
||||
#include <Kernel/Thread.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
#define ENTER_THREAD_CONTEXT_ARGS_SIZE (2 * 4) // to_thread, from_thread
|
||||
|
||||
NAKED void thread_context_first_enter(void)
|
||||
{
|
||||
// clang-format off
|
||||
// enter_thread_context returns to here first time a thread is executing
|
||||
asm(
|
||||
// switch_context will have pushed from_thread and to_thread to our new
|
||||
// stack prior to thread_context_first_enter() being called, and the
|
||||
// pointer to TrapFrame was the top of the stack before that
|
||||
" movl 8(%esp), %ebx \n" // save pointer to TrapFrame
|
||||
" cld \n"
|
||||
" call context_first_init \n"
|
||||
" addl $" __STRINGIFY(ENTER_THREAD_CONTEXT_ARGS_SIZE) ", %esp \n"
|
||||
" movl %ebx, 0(%esp) \n" // push pointer to TrapFrame
|
||||
" jmp common_trap_exit \n"
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
NAKED void do_assume_context(Thread*, u32)
|
||||
{
|
||||
// clang-format off
|
||||
// FIXME: I hope (Thread* thread, u32 flags) aren't compiled away
|
||||
asm(
|
||||
" movl 4(%esp), %ebx \n"
|
||||
" movl 8(%esp), %esi \n"
|
||||
// We're going to call Processor::init_context, so just make sure
|
||||
// we have enough stack space so we don't stomp over it
|
||||
" subl $(" __STRINGIFY(4 + REGISTER_STATE_SIZE + TRAP_FRAME_SIZE + 4) "), %esp \n"
|
||||
" pushl %esi \n"
|
||||
" pushl %ebx \n"
|
||||
" cld \n"
|
||||
" call do_init_context \n"
|
||||
" addl $8, %esp \n"
|
||||
" movl %eax, %esp \n" // move stack pointer to what Processor::init_context set up for us
|
||||
" pushl %ebx \n" // push to_thread
|
||||
" pushl %ebx \n" // push from_thread
|
||||
" pushl $thread_context_first_enter \n" // should be same as regs.eip
|
||||
" jmp enter_thread_context \n"
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
StringView Processor::platform_string()
|
||||
{
|
||||
return "i386"sv;
|
||||
}
|
||||
|
||||
FlatPtr Processor::init_context(Thread& thread, bool leave_crit)
|
||||
{
|
||||
VERIFY(is_kernel_mode());
|
||||
VERIFY(g_scheduler_lock.is_locked());
|
||||
if (leave_crit) {
|
||||
// Leave the critical section we set up in Process::exec,
|
||||
// but because we still have the scheduler lock we should end up with 1
|
||||
VERIFY(in_critical() == 2);
|
||||
m_in_critical = 1; // leave it without triggering anything or restoring flags
|
||||
}
|
||||
|
||||
u32 kernel_stack_top = thread.kernel_stack_top();
|
||||
|
||||
// Add a random offset between 0-256 (16-byte aligned)
|
||||
kernel_stack_top -= round_up_to_power_of_two(get_fast_random<u8>(), 16);
|
||||
|
||||
u32 stack_top = kernel_stack_top;
|
||||
|
||||
// TODO: handle NT?
|
||||
VERIFY((cpu_flags() & 0x24000) == 0); // Assume !(NT | VM)
|
||||
|
||||
auto& regs = thread.regs();
|
||||
bool return_to_user = (regs.cs & 3) != 0;
|
||||
|
||||
// make room for an interrupt frame
|
||||
if (!return_to_user) {
|
||||
// userspace_esp and userspace_ss are not popped off by iret
|
||||
// unless we're switching back to user mode
|
||||
stack_top -= sizeof(RegisterState) - 2 * sizeof(u32);
|
||||
|
||||
// For kernel threads we'll push the thread function argument
|
||||
// which should be in regs.esp and exit_kernel_thread as return
|
||||
// address.
|
||||
stack_top -= 2 * sizeof(u32);
|
||||
*reinterpret_cast<u32*>(kernel_stack_top - 2 * sizeof(u32)) = regs.esp;
|
||||
*reinterpret_cast<u32*>(kernel_stack_top - 3 * sizeof(u32)) = FlatPtr(&exit_kernel_thread);
|
||||
} else {
|
||||
stack_top -= sizeof(RegisterState);
|
||||
}
|
||||
|
||||
// we want to end up 16-byte aligned, %esp + 4 should be aligned
|
||||
stack_top -= sizeof(u32);
|
||||
*reinterpret_cast<u32*>(kernel_stack_top - sizeof(u32)) = 0;
|
||||
|
||||
// set up the stack so that after returning from thread_context_first_enter()
|
||||
// we will end up either in kernel mode or user mode, depending on how the thread is set up
|
||||
// However, the first step is to always start in kernel mode with thread_context_first_enter
|
||||
RegisterState& iretframe = *reinterpret_cast<RegisterState*>(stack_top);
|
||||
iretframe.ss = regs.ss;
|
||||
iretframe.gs = regs.gs;
|
||||
iretframe.fs = regs.fs;
|
||||
iretframe.es = regs.es;
|
||||
iretframe.ds = regs.ds;
|
||||
iretframe.edi = regs.edi;
|
||||
iretframe.esi = regs.esi;
|
||||
iretframe.ebp = regs.ebp;
|
||||
iretframe.esp = 0;
|
||||
iretframe.ebx = regs.ebx;
|
||||
iretframe.edx = regs.edx;
|
||||
iretframe.ecx = regs.ecx;
|
||||
iretframe.eax = regs.eax;
|
||||
iretframe.eflags = regs.eflags;
|
||||
iretframe.eip = regs.eip;
|
||||
iretframe.cs = regs.cs;
|
||||
if (return_to_user) {
|
||||
iretframe.userspace_esp = regs.esp;
|
||||
iretframe.userspace_ss = regs.ss;
|
||||
}
|
||||
|
||||
// make space for a trap frame
|
||||
stack_top -= sizeof(TrapFrame);
|
||||
TrapFrame& trap = *reinterpret_cast<TrapFrame*>(stack_top);
|
||||
trap.regs = &iretframe;
|
||||
trap.prev_irq_level = 0;
|
||||
trap.next_trap = nullptr;
|
||||
|
||||
stack_top -= sizeof(u32); // pointer to TrapFrame
|
||||
*reinterpret_cast<u32*>(stack_top) = stack_top + 4;
|
||||
|
||||
if constexpr (CONTEXT_SWITCH_DEBUG) {
|
||||
if (return_to_user) {
|
||||
dbgln("init_context {} ({}) set up to execute at eip={}:{}, esp={}, stack_top={}, user_top={}:{}",
|
||||
thread,
|
||||
VirtualAddress(&thread),
|
||||
iretframe.cs, regs.eip,
|
||||
VirtualAddress(regs.esp),
|
||||
VirtualAddress(stack_top),
|
||||
iretframe.userspace_ss,
|
||||
iretframe.userspace_esp);
|
||||
} else {
|
||||
dbgln("init_context {} ({}) set up to execute at eip={}:{}, esp={}, stack_top={}",
|
||||
thread,
|
||||
VirtualAddress(&thread),
|
||||
iretframe.cs, regs.eip,
|
||||
VirtualAddress(regs.esp),
|
||||
VirtualAddress(stack_top));
|
||||
}
|
||||
}
|
||||
|
||||
// make switch_context() always first return to thread_context_first_enter()
|
||||
// in kernel mode, so set up these values so that we end up popping iretframe
|
||||
// off the stack right after the context switch completed, at which point
|
||||
// control is transferred to what iretframe is pointing to.
|
||||
regs.eip = FlatPtr(&thread_context_first_enter);
|
||||
regs.esp0 = kernel_stack_top;
|
||||
regs.esp = stack_top;
|
||||
regs.cs = GDT_SELECTOR_CODE0;
|
||||
regs.ds = GDT_SELECTOR_DATA0;
|
||||
regs.es = GDT_SELECTOR_DATA0;
|
||||
regs.fs = GDT_SELECTOR_DATA0;
|
||||
regs.ss = GDT_SELECTOR_DATA0;
|
||||
regs.gs = GDT_SELECTOR_PROC;
|
||||
return stack_top;
|
||||
}
|
||||
|
||||
void Processor::switch_context(Thread*& from_thread, Thread*& to_thread)
|
||||
{
|
||||
VERIFY(!m_in_irq);
|
||||
VERIFY(m_in_critical == 1);
|
||||
VERIFY(is_kernel_mode());
|
||||
|
||||
dbgln_if(CONTEXT_SWITCH_DEBUG, "switch_context --> switching out of: {} {}", VirtualAddress(from_thread), *from_thread);
|
||||
|
||||
// m_in_critical is restored in enter_thread_context
|
||||
from_thread->save_critical(m_in_critical);
|
||||
|
||||
// clang-format off
|
||||
// Switch to new thread context, passing from_thread and to_thread
|
||||
// through to the new context using registers edx and eax
|
||||
asm volatile(
|
||||
// NOTE: changing how much we push to the stack affects thread_context_first_enter()!
|
||||
"pushfl \n"
|
||||
"pushl %%ebx \n"
|
||||
"pushl %%esi \n"
|
||||
"pushl %%edi \n"
|
||||
"pushl %%ebp \n"
|
||||
"movl %%esp, %[from_esp] \n"
|
||||
"movl $1f, %[from_eip] \n"
|
||||
"movl %[to_esp0], %%ebx \n"
|
||||
"movl %%ebx, %[tss_esp0] \n"
|
||||
"movl %[to_esp], %%esp \n"
|
||||
"pushl %[to_thread] \n"
|
||||
"pushl %[from_thread] \n"
|
||||
"pushl %[to_eip] \n"
|
||||
"cld \n"
|
||||
"jmp enter_thread_context \n"
|
||||
"1: \n"
|
||||
"popl %%edx \n"
|
||||
"popl %%eax \n"
|
||||
"popl %%ebp \n"
|
||||
"popl %%edi \n"
|
||||
"popl %%esi \n"
|
||||
"popl %%ebx \n"
|
||||
"popfl \n"
|
||||
: [from_esp] "=m" (from_thread->regs().esp),
|
||||
[from_eip] "=m" (from_thread->regs().eip),
|
||||
[tss_esp0] "=m" (m_tss.esp0),
|
||||
"=d" (from_thread), // needed so that from_thread retains the correct value
|
||||
"=a" (to_thread) // needed so that to_thread retains the correct value
|
||||
: [to_esp] "g" (to_thread->regs().esp),
|
||||
[to_esp0] "g" (to_thread->regs().esp0),
|
||||
[to_eip] "c" (to_thread->regs().eip),
|
||||
[from_thread] "d" (from_thread),
|
||||
[to_thread] "a" (to_thread)
|
||||
: "memory"
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
dbgln_if(CONTEXT_SWITCH_DEBUG, "switch_context <-- from {} {} to {} {}", VirtualAddress(from_thread), *from_thread, VirtualAddress(to_thread), *to_thread);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void Processor::initialize_context_switching(Thread& initial_thread)
|
||||
{
|
||||
VERIFY(initial_thread.process().is_kernel_process());
|
||||
|
||||
auto& regs = initial_thread.regs();
|
||||
m_tss.iomapbase = sizeof(m_tss);
|
||||
m_tss.esp0 = regs.esp0;
|
||||
m_tss.ss0 = GDT_SELECTOR_DATA0;
|
||||
|
||||
m_scheduler_initialized = true;
|
||||
|
||||
// clang-format off
|
||||
asm volatile(
|
||||
"movl %[new_esp], %%esp \n" // switch to new stack
|
||||
"pushl %[from_to_thread] \n" // to_thread
|
||||
"pushl %[from_to_thread] \n" // from_thread
|
||||
"pushl $" __STRINGIFY(GDT_SELECTOR_CODE0) " \n"
|
||||
"pushl %[new_eip] \n" // save the entry eip to the stack
|
||||
"movl %%esp, %%ebx \n"
|
||||
"addl $20, %%ebx \n" // calculate pointer to TrapFrame
|
||||
"pushl %%ebx \n"
|
||||
"cld \n"
|
||||
"pushl %[cpu] \n" // push argument for init_finished before register is clobbered
|
||||
"call pre_init_finished \n"
|
||||
"call init_finished \n"
|
||||
"addl $4, %%esp \n"
|
||||
"call post_init_finished \n"
|
||||
"call enter_trap_no_irq \n"
|
||||
"addl $4, %%esp \n"
|
||||
"lret \n"
|
||||
:: [new_esp] "g" (regs.esp),
|
||||
[new_eip] "a" (regs.eip),
|
||||
[from_to_thread] "b" (&initial_thread),
|
||||
[cpu] "c" (Processor::current_id())
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
@ -1,283 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <Kernel/Arch/Processor.h>
|
||||
#include <Kernel/Arch/x86/TrapFrame.h>
|
||||
#include <Kernel/Panic.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/Random.h>
|
||||
#include <Kernel/Scheduler.h>
|
||||
#include <Kernel/Sections.h>
|
||||
#include <Kernel/Thread.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
NAKED void thread_context_first_enter(void)
|
||||
{
|
||||
// enter_thread_context returns to here first time a thread is executing
|
||||
asm(
|
||||
// switch_context will have pushed from_thread and to_thread to our news
|
||||
// stack prior to thread_context_first_enter() being called, and the
|
||||
// pointer to TrapFrame was the top of the stack before that
|
||||
" popq %rdi \n" // from_thread (argument 0)
|
||||
" popq %rsi \n" // to_thread (argument 1)
|
||||
" popq %rdx \n" // pointer to TrapFrame (argument 2)
|
||||
" cld \n"
|
||||
" call context_first_init \n"
|
||||
" jmp common_trap_exit \n");
|
||||
};
|
||||
|
||||
NAKED void do_assume_context(Thread*, u32)
|
||||
{
|
||||
// clang-format off
|
||||
// FIXME: I hope (Thread* thread, u32 flags) aren't compiled away
|
||||
asm(
|
||||
" movq %rdi, %r12 \n" // save thread ptr
|
||||
" movq %rsi, %r13 \n" // save flags
|
||||
// We're going to call Processor::init_context, so just make sure
|
||||
// we have enough stack space so we don't stomp over it
|
||||
" subq $(" __STRINGIFY(16 + REGISTER_STATE_SIZE + TRAP_FRAME_SIZE + 8) "), %rsp \n"
|
||||
" cld \n"
|
||||
" call do_init_context \n"
|
||||
" movq %rax, %rsp \n" // move stack pointer to what Processor::init_context set up for us
|
||||
" movq %r12, %rdi \n" // to_thread
|
||||
" movq %r12, %rsi \n" // from_thread
|
||||
" pushq %r12 \n" // to_thread (for thread_context_first_enter)
|
||||
" pushq %r12 \n" // from_thread (for thread_context_first_enter)
|
||||
" leaq thread_context_first_enter(%rip), %r12 \n" // should be same as regs.rip
|
||||
" pushq %r12 \n"
|
||||
" jmp enter_thread_context \n");
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
StringView Processor::platform_string()
|
||||
{
|
||||
return "x86_64"sv;
|
||||
}
|
||||
|
||||
// FIXME: For the most part this is a copy of the i386-specific function, get rid of the code duplication
|
||||
FlatPtr Processor::init_context(Thread& thread, bool leave_crit)
|
||||
{
|
||||
VERIFY(is_kernel_mode());
|
||||
VERIFY(g_scheduler_lock.is_locked());
|
||||
if (leave_crit) {
|
||||
// Leave the critical section we set up in Process::exec,
|
||||
// but because we still have the scheduler lock we should end up with 1
|
||||
VERIFY(in_critical() == 2);
|
||||
m_in_critical = 1; // leave it without triggering anything or restoring flags
|
||||
}
|
||||
|
||||
u64 kernel_stack_top = thread.kernel_stack_top();
|
||||
|
||||
// Add a random offset between 0-256 (16-byte aligned)
|
||||
kernel_stack_top -= round_up_to_power_of_two(get_fast_random<u8>(), 16);
|
||||
|
||||
u64 stack_top = kernel_stack_top;
|
||||
|
||||
// TODO: handle NT?
|
||||
VERIFY((cpu_flags() & 0x24000) == 0); // Assume !(NT | VM)
|
||||
|
||||
auto& regs = thread.regs();
|
||||
bool return_to_user = (regs.cs & 3) != 0;
|
||||
|
||||
stack_top -= 1 * sizeof(u64);
|
||||
*reinterpret_cast<u64*>(kernel_stack_top - 2 * sizeof(u64)) = FlatPtr(&exit_kernel_thread);
|
||||
|
||||
stack_top -= sizeof(RegisterState);
|
||||
|
||||
// we want to end up 16-byte aligned, %rsp + 8 should be aligned
|
||||
stack_top -= sizeof(u64);
|
||||
*reinterpret_cast<u64*>(kernel_stack_top - sizeof(u64)) = 0;
|
||||
|
||||
// set up the stack so that after returning from thread_context_first_enter()
|
||||
// we will end up either in kernel mode or user mode, depending on how the thread is set up
|
||||
// However, the first step is to always start in kernel mode with thread_context_first_enter
|
||||
RegisterState& iretframe = *reinterpret_cast<RegisterState*>(stack_top);
|
||||
iretframe.rdi = regs.rdi;
|
||||
iretframe.rsi = regs.rsi;
|
||||
iretframe.rbp = regs.rbp;
|
||||
iretframe.rsp = 0;
|
||||
iretframe.rbx = regs.rbx;
|
||||
iretframe.rdx = regs.rdx;
|
||||
iretframe.rcx = regs.rcx;
|
||||
iretframe.rax = regs.rax;
|
||||
iretframe.r8 = regs.r8;
|
||||
iretframe.r9 = regs.r9;
|
||||
iretframe.r10 = regs.r10;
|
||||
iretframe.r11 = regs.r11;
|
||||
iretframe.r12 = regs.r12;
|
||||
iretframe.r13 = regs.r13;
|
||||
iretframe.r14 = regs.r14;
|
||||
iretframe.r15 = regs.r15;
|
||||
iretframe.rflags = regs.rflags;
|
||||
iretframe.rip = regs.rip;
|
||||
iretframe.cs = regs.cs;
|
||||
if (return_to_user) {
|
||||
iretframe.userspace_rsp = regs.rsp;
|
||||
iretframe.userspace_ss = GDT_SELECTOR_DATA3 | 3;
|
||||
} else {
|
||||
iretframe.userspace_rsp = kernel_stack_top;
|
||||
iretframe.userspace_ss = 0;
|
||||
}
|
||||
|
||||
// make space for a trap frame
|
||||
stack_top -= sizeof(TrapFrame);
|
||||
TrapFrame& trap = *reinterpret_cast<TrapFrame*>(stack_top);
|
||||
trap.regs = &iretframe;
|
||||
trap.prev_irq_level = 0;
|
||||
trap.next_trap = nullptr;
|
||||
|
||||
stack_top -= sizeof(u64); // pointer to TrapFrame
|
||||
*reinterpret_cast<u64*>(stack_top) = stack_top + 8;
|
||||
|
||||
if constexpr (CONTEXT_SWITCH_DEBUG) {
|
||||
if (return_to_user) {
|
||||
dbgln("init_context {} ({}) set up to execute at rip={}:{}, rsp={}, stack_top={}, user_top={}",
|
||||
thread,
|
||||
VirtualAddress(&thread),
|
||||
iretframe.cs, regs.rip,
|
||||
VirtualAddress(regs.rsp),
|
||||
VirtualAddress(stack_top),
|
||||
iretframe.userspace_rsp);
|
||||
} else {
|
||||
dbgln("init_context {} ({}) set up to execute at rip={}:{}, rsp={}, stack_top={}",
|
||||
thread,
|
||||
VirtualAddress(&thread),
|
||||
iretframe.cs, regs.rip,
|
||||
VirtualAddress(regs.rsp),
|
||||
VirtualAddress(stack_top));
|
||||
}
|
||||
}
|
||||
|
||||
// make switch_context() always first return to thread_context_first_enter()
|
||||
// in kernel mode, so set up these values so that we end up popping iretframe
|
||||
// off the stack right after the context switch completed, at which point
|
||||
// control is transferred to what iretframe is pointing to.
|
||||
regs.rip = FlatPtr(&thread_context_first_enter);
|
||||
regs.rsp0 = kernel_stack_top;
|
||||
regs.rsp = stack_top;
|
||||
regs.cs = GDT_SELECTOR_CODE0;
|
||||
return stack_top;
|
||||
}
|
||||
|
||||
void Processor::switch_context(Thread*& from_thread, Thread*& to_thread)
|
||||
{
|
||||
VERIFY(!m_in_irq);
|
||||
VERIFY(m_in_critical == 1);
|
||||
VERIFY(is_kernel_mode());
|
||||
|
||||
dbgln_if(CONTEXT_SWITCH_DEBUG, "switch_context --> switching out of: {} {}", VirtualAddress(from_thread), *from_thread);
|
||||
|
||||
// m_in_critical is restored in enter_thread_context
|
||||
from_thread->save_critical(m_in_critical);
|
||||
|
||||
// clang-format off
|
||||
// Switch to new thread context, passing from_thread and to_thread
|
||||
// through to the new context using registers rdx and rax
|
||||
asm volatile(
|
||||
// NOTE: changing how much we push to the stack affects thread_context_first_enter()!
|
||||
"pushfq \n"
|
||||
"pushq %%rbx \n"
|
||||
"pushq %%rcx \n"
|
||||
"pushq %%rbp \n"
|
||||
"pushq %%rsi \n"
|
||||
"pushq %%rdi \n"
|
||||
"pushq %%r8 \n"
|
||||
"pushq %%r9 \n"
|
||||
"pushq %%r10 \n"
|
||||
"pushq %%r11 \n"
|
||||
"pushq %%r12 \n"
|
||||
"pushq %%r13 \n"
|
||||
"pushq %%r14 \n"
|
||||
"pushq %%r15 \n"
|
||||
"movq %%rsp, %[from_rsp] \n"
|
||||
"leaq 1f(%%rip), %%rbx \n"
|
||||
"movq %%rbx, %[from_rip] \n"
|
||||
"movq %[to_rsp0], %%rbx \n"
|
||||
"movl %%ebx, %[tss_rsp0l] \n"
|
||||
"shrq $32, %%rbx \n"
|
||||
"movl %%ebx, %[tss_rsp0h] \n"
|
||||
"movq %[to_rsp], %%rsp \n"
|
||||
"pushq %[to_thread] \n"
|
||||
"pushq %[from_thread] \n"
|
||||
"pushq %[to_rip] \n"
|
||||
"cld \n"
|
||||
"movq 16(%%rsp), %%rsi \n"
|
||||
"movq 8(%%rsp), %%rdi \n"
|
||||
"jmp enter_thread_context \n"
|
||||
"1: \n"
|
||||
"popq %%rdx \n"
|
||||
"popq %%rax \n"
|
||||
"popq %%r15 \n"
|
||||
"popq %%r14 \n"
|
||||
"popq %%r13 \n"
|
||||
"popq %%r12 \n"
|
||||
"popq %%r11 \n"
|
||||
"popq %%r10 \n"
|
||||
"popq %%r9 \n"
|
||||
"popq %%r8 \n"
|
||||
"popq %%rdi \n"
|
||||
"popq %%rsi \n"
|
||||
"popq %%rbp \n"
|
||||
"popq %%rcx \n"
|
||||
"popq %%rbx \n"
|
||||
"popfq \n"
|
||||
: [from_rsp] "=m" (from_thread->regs().rsp),
|
||||
[from_rip] "=m" (from_thread->regs().rip),
|
||||
[tss_rsp0l] "=m" (m_tss.rsp0l),
|
||||
[tss_rsp0h] "=m" (m_tss.rsp0h),
|
||||
"=d" (from_thread), // needed so that from_thread retains the correct value
|
||||
"=a" (to_thread) // needed so that to_thread retains the correct value
|
||||
: [to_rsp] "g" (to_thread->regs().rsp),
|
||||
[to_rsp0] "g" (to_thread->regs().rsp0),
|
||||
[to_rip] "c" (to_thread->regs().rip),
|
||||
[from_thread] "d" (from_thread),
|
||||
[to_thread] "a" (to_thread)
|
||||
: "memory", "rbx"
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
dbgln_if(CONTEXT_SWITCH_DEBUG, "switch_context <-- from {} {} to {} {}", VirtualAddress(from_thread), *from_thread, VirtualAddress(to_thread), *to_thread);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void Processor::initialize_context_switching(Thread& initial_thread)
|
||||
{
|
||||
VERIFY(initial_thread.process().is_kernel_process());
|
||||
|
||||
auto& regs = initial_thread.regs();
|
||||
m_tss.iomapbase = sizeof(m_tss);
|
||||
m_tss.rsp0l = regs.rsp0 & 0xffffffff;
|
||||
m_tss.rsp0h = regs.rsp0 >> 32;
|
||||
|
||||
m_scheduler_initialized = true;
|
||||
|
||||
// clang-format off
|
||||
asm volatile(
|
||||
"movq %[new_rsp], %%rsp \n" // switch to new stack
|
||||
"pushq %[from_to_thread] \n" // to_thread
|
||||
"pushq %[from_to_thread] \n" // from_thread
|
||||
"pushq %[new_rip] \n" // save the entry rip to the stack
|
||||
"cld \n"
|
||||
"pushq %[cpu] \n" // push argument for init_finished before register is clobbered
|
||||
"call pre_init_finished \n"
|
||||
"pop %%rdi \n" // move argument for init_finished into place
|
||||
"call init_finished \n"
|
||||
"call post_init_finished \n"
|
||||
"movq 24(%%rsp), %%rdi \n" // move pointer to TrapFrame into place
|
||||
"call enter_trap_no_irq \n"
|
||||
"retq \n"
|
||||
:: [new_rsp] "g" (regs.rsp),
|
||||
[new_rip] "a" (regs.rip),
|
||||
[from_to_thread] "b" (&initial_thread),
|
||||
[cpu] "c" ((u64)id())
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
@ -6,11 +6,46 @@
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
#include <Kernel/Arch/x86/ASM_wrapper.h>
|
||||
#include <Kernel/Arch/Processor.h>
|
||||
#include <Kernel/Arch/x86_64/ASM_wrapper.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
#define XCR_XFEATURE_ENABLED_MASK 0
|
||||
|
||||
UNMAP_AFTER_INIT u64 read_xcr0()
|
||||
{
|
||||
u32 eax, edx;
|
||||
asm volatile("xgetbv"
|
||||
: "=a"(eax), "=d"(edx)
|
||||
: "c"(XCR_XFEATURE_ENABLED_MASK));
|
||||
return eax + ((u64)edx << 32);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void write_xcr0(u64 value)
|
||||
{
|
||||
u32 eax = value;
|
||||
u32 edx = value >> 32;
|
||||
asm volatile("xsetbv" ::"a"(eax), "d"(edx), "c"(XCR_XFEATURE_ENABLED_MASK));
|
||||
}
|
||||
|
||||
void stac()
|
||||
{
|
||||
if (!Processor::current().has_feature(CPUFeature::SMAP))
|
||||
return;
|
||||
asm volatile("stac" ::
|
||||
: "cc");
|
||||
}
|
||||
|
||||
void clac()
|
||||
{
|
||||
if (!Processor::current().has_feature(CPUFeature::SMAP))
|
||||
return;
|
||||
asm volatile("clac" ::
|
||||
: "cc");
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void write_cr0(FlatPtr value)
|
||||
{
|
||||
asm volatile("mov %%rax, %%cr0" ::"a"(value));
|
@ -4,8 +4,8 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/common/CMOS.h>
|
||||
#include <Kernel/Arch/x86_64/CMOS.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
|
||||
namespace Kernel::CMOS {
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <AK/Concepts.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
#include <Kernel/Arch/x86/DescriptorTable.h>
|
||||
#include <Kernel/Arch/x86_64/DescriptorTable.h>
|
||||
|
||||
#include <AK/Platform.h>
|
||||
VALIDATE_IS_X86()
|
@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/CPUID.h>
|
||||
#include <Kernel/Arch/x86_64/CPUID.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/CurrentTime.h>
|
||||
#include <Kernel/Arch/x86/ASM_wrapper.h>
|
||||
#include <Kernel/Arch/x86/Processor.h>
|
||||
#include <Kernel/Arch/x86_64/ASM_wrapper.h>
|
||||
#include <Kernel/Arch/x86_64/Processor.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/DebugOutput.h>
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/common/BochsDebugOutput.h>
|
||||
#include <Kernel/Arch/x86_64/BochsDebugOutput.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/Delay.h>
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <AK/Platform.h>
|
||||
#include <Kernel/Arch/x86/Hypervisor/BochsDisplayConnector.h>
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86_64/Hypervisor/BochsDisplayConnector.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Bus/PCI/Access.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/Devices/DeviceManagement.h>
|
@ -7,7 +7,7 @@
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Singleton.h>
|
||||
#include <Kernel/API/MousePacket.h>
|
||||
#include <Kernel/Arch/x86/Hypervisor/VMWareBackdoor.h>
|
||||
#include <Kernel/Arch/x86_64/Hypervisor/VMWareBackdoor.h>
|
||||
#include <Kernel/CommandLine.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/InterruptDisabler.h>
|
@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <AK/Format.h>
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/common/I8042Reboot.h>
|
||||
#include <Kernel/Arch/x86_64/I8042Reboot.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/x86/ISABus/HID/PS2KeyboardDevice.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/Devices/DeviceManagement.h>
|
||||
#include <Kernel/Devices/HID/HIDManagement.h>
|
@ -9,7 +9,7 @@
|
||||
#include <AK/CircularQueue.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/API/KeyCode.h>
|
||||
#include <Kernel/Arch/x86/ISABus/I8042Controller.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/I8042Controller.h>
|
||||
#include <Kernel/Devices/HID/KeyboardDevice.h>
|
||||
#include <Kernel/Interrupts/IRQHandler.h>
|
||||
#include <Kernel/Random.h>
|
@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <AK/Memory.h>
|
||||
#include <Kernel/Arch/x86/Hypervisor/VMWareBackdoor.h>
|
||||
#include <Kernel/Arch/x86/ISABus/HID/PS2MouseDevice.h>
|
||||
#include <Kernel/Arch/x86_64/Hypervisor/VMWareBackdoor.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/Devices/DeviceManagement.h>
|
||||
#include <Kernel/Sections.h>
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include <AK/CircularQueue.h>
|
||||
#include <Kernel/API/MousePacket.h>
|
||||
#include <Kernel/Arch/x86/ISABus/I8042Controller.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/I8042Controller.h>
|
||||
#include <Kernel/Devices/HID/MouseDevice.h>
|
||||
#include <Kernel/Interrupts/IRQHandler.h>
|
||||
#include <Kernel/Random.h>
|
@ -4,8 +4,8 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/Hypervisor/VMWareBackdoor.h>
|
||||
#include <Kernel/Arch/x86/ISABus/HID/VMWareMouseDevice.h>
|
||||
#include <Kernel/Arch/x86_64/Hypervisor/VMWareBackdoor.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.h>
|
||||
#include <Kernel/Devices/DeviceManagement.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
#include <AK/CircularQueue.h>
|
||||
#include <Kernel/API/MousePacket.h>
|
||||
#include <Kernel/Arch/x86/ISABus/HID/PS2MouseDevice.h>
|
||||
#include <Kernel/Arch/x86/ISABus/I8042Controller.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/I8042Controller.h>
|
||||
#include <Kernel/Interrupts/IRQHandler.h>
|
||||
#include <Kernel/Random.h>
|
||||
|
@ -5,11 +5,11 @@
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/Delay.h>
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/ISABus/HID/PS2KeyboardDevice.h>
|
||||
#include <Kernel/Arch/x86/ISABus/HID/PS2MouseDevice.h>
|
||||
#include <Kernel/Arch/x86/ISABus/HID/VMWareMouseDevice.h>
|
||||
#include <Kernel/Arch/x86/ISABus/I8042Controller.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/I8042Controller.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
||||
namespace Kernel {
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/x86/ISABus/IDEController.h>
|
||||
#include <Kernel/Arch/x86_64/ISABus/IDEController.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Library/LockRefPtr.h>
|
||||
#include <Kernel/Sections.h>
|
@ -6,7 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Kernel/Arch/x86/Interrupts.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts.h>
|
||||
|
||||
#include <AK/Platform.h>
|
||||
VALIDATE_IS_X86()
|
@ -5,8 +5,8 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/DescriptorTable.h>
|
||||
#include <Kernel/Arch/x86/TrapFrame.h>
|
||||
#include <Kernel/Arch/x86_64/DescriptorTable.h>
|
||||
#include <Kernel/Arch/x86_64/TrapFrame.h>
|
||||
|
||||
// clang-format off
|
||||
asm(
|
@ -7,10 +7,10 @@
|
||||
#include <AK/ByteReader.h>
|
||||
#include <Kernel/API/Syscall.h>
|
||||
#include <Kernel/Arch/Interrupts.h>
|
||||
#include <Kernel/Arch/x86/InterruptManagement.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/IOAPIC.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/PIC.h>
|
||||
#include <Kernel/Arch/x86_64/InterruptManagement.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/IOAPIC.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/PIC.h>
|
||||
#include <Kernel/CommandLine.h>
|
||||
#include <Kernel/Firmware/MultiProcessor/Parser.h>
|
||||
#include <Kernel/InterruptDisabler.h>
|
@ -10,8 +10,8 @@
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/x86/IRQController.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/IOAPIC.h>
|
||||
#include <Kernel/Arch/x86_64/IRQController.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/IOAPIC.h>
|
||||
#include <Kernel/Firmware/ACPI/Definitions.h>
|
||||
#include <Kernel/Interrupts/GenericInterruptHandler.h>
|
||||
#include <Kernel/Library/LockRefPtr.h>
|
@ -9,7 +9,7 @@
|
||||
#include <AK/Types.h>
|
||||
|
||||
#include <Kernel/Arch/Interrupts.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/PIC.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/PIC.h>
|
||||
#include <Kernel/Interrupts/GenericInterruptHandler.h>
|
||||
#include <Kernel/Interrupts/SharedIRQHandler.h>
|
||||
#include <Kernel/Interrupts/SpuriousInterruptHandler.h>
|
||||
@ -31,7 +31,7 @@
|
||||
#include <Kernel/Arch/RegisterState.h>
|
||||
#include <Kernel/Arch/SafeMem.h>
|
||||
#include <Kernel/Arch/TrapFrame.h>
|
||||
#include <Kernel/Arch/x86/ISRStubs.h>
|
||||
#include <Kernel/Arch/x86_64/ISRStubs.h>
|
||||
|
||||
extern FlatPtr start_of_unmap_after_init;
|
||||
extern FlatPtr end_of_unmap_after_init;
|
@ -9,10 +9,10 @@
|
||||
#include <AK/Singleton.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/Delay.h>
|
||||
#include <Kernel/Arch/x86/MSR.h>
|
||||
#include <Kernel/Arch/x86/ProcessorInfo.h>
|
||||
#include <Kernel/Arch/x86/Time/APICTimer.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86_64/MSR.h>
|
||||
#include <Kernel/Arch/x86_64/ProcessorInfo.h>
|
||||
#include <Kernel/Arch/x86_64/Time/APICTimer.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/Firmware/ACPI/Parser.h>
|
||||
#include <Kernel/Interrupts/SpuriousInterruptHandler.h>
|
@ -5,9 +5,9 @@
|
||||
*/
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <Kernel/Arch/x86/InterruptManagement.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/IOAPIC.h>
|
||||
#include <Kernel/Arch/x86_64/InterruptManagement.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/IOAPIC.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/InterruptDisabler.h>
|
||||
#include <Kernel/Sections.h>
|
@ -6,7 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Kernel/Arch/x86/IRQController.h>
|
||||
#include <Kernel/Arch/x86_64/IRQController.h>
|
||||
#include <Kernel/Memory/TypedMapping.h>
|
||||
|
||||
namespace Kernel {
|
@ -6,8 +6,8 @@
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/PIC.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/PIC.h>
|
||||
#include <Kernel/InterruptDisabler.h>
|
||||
#include <Kernel/Interrupts/GenericInterruptHandler.h>
|
||||
#include <Kernel/Sections.h>
|
@ -7,7 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/x86/IRQController.h>
|
||||
#include <Kernel/Arch/x86_64/IRQController.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
#include <Kernel/Arch/x86/CPUID.h>
|
||||
#include <Kernel/Arch/x86_64/CPUID.h>
|
||||
|
||||
#include <AK/Platform.h>
|
||||
VALIDATE_IS_X86()
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -4,8 +4,8 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/PCI/Controller/HostBridge.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Arch/x86_64/PCI/Controller/HostBridge.h>
|
||||
#include <Kernel/Bus/PCI/Access.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/x86/PCI/IDELegacyModeController.h>
|
||||
#include <Kernel/Arch/x86_64/PCI/IDELegacyModeController.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Library/LockRefPtr.h>
|
||||
#include <Kernel/Sections.h>
|
@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Bus/PCI/Access.h>
|
||||
#include <Kernel/Bus/PCI/Initializer.h>
|
@ -4,9 +4,9 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/Time/PIT.h>
|
||||
#include <Kernel/Arch/x86/common/PCSpeaker.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Arch/x86_64/PCSpeaker.h>
|
||||
#include <Kernel/Arch/x86_64/Time/PIT.h>
|
||||
|
||||
void PCSpeaker::tone_on(int frequency)
|
||||
{
|
@ -12,7 +12,7 @@
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
#include <Kernel/Arch/x86/common/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/APIC.h>
|
||||
#include <Kernel/InterruptDisabler.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/Scheduler.h>
|
||||
@ -25,9 +25,9 @@
|
||||
#include <Kernel/Arch/SafeMem.h>
|
||||
#include <Kernel/Arch/ScopedCritical.h>
|
||||
#include <Kernel/Arch/TrapFrame.h>
|
||||
#include <Kernel/Arch/x86/CPUID.h>
|
||||
#include <Kernel/Arch/x86/MSR.h>
|
||||
#include <Kernel/Arch/x86/ProcessorInfo.h>
|
||||
#include <Kernel/Arch/x86_64/CPUID.h>
|
||||
#include <Kernel/Arch/x86_64/MSR.h>
|
||||
#include <Kernel/Arch/x86_64/ProcessorInfo.h>
|
||||
|
||||
#include <Kernel/Memory/PageDirectory.h>
|
||||
#include <Kernel/Memory/ScopedAddressSpaceSwitcher.h>
|
||||
@ -1623,4 +1623,268 @@ u32 Processor::clear_critical()
|
||||
return prev_critical;
|
||||
}
|
||||
|
||||
NAKED void thread_context_first_enter(void)
|
||||
{
|
||||
// enter_thread_context returns to here first time a thread is executing
|
||||
asm(
|
||||
// switch_context will have pushed from_thread and to_thread to our news
|
||||
// stack prior to thread_context_first_enter() being called, and the
|
||||
// pointer to TrapFrame was the top of the stack before that
|
||||
" popq %rdi \n" // from_thread (argument 0)
|
||||
" popq %rsi \n" // to_thread (argument 1)
|
||||
" popq %rdx \n" // pointer to TrapFrame (argument 2)
|
||||
" cld \n"
|
||||
" call context_first_init \n"
|
||||
" jmp common_trap_exit \n");
|
||||
};
|
||||
|
||||
NAKED void do_assume_context(Thread*, u32)
|
||||
{
|
||||
// clang-format off
|
||||
// FIXME: I hope (Thread* thread, u32 flags) aren't compiled away
|
||||
asm(
|
||||
" movq %rdi, %r12 \n" // save thread ptr
|
||||
" movq %rsi, %r13 \n" // save flags
|
||||
// We're going to call Processor::init_context, so just make sure
|
||||
// we have enough stack space so we don't stomp over it
|
||||
" subq $(" __STRINGIFY(16 + REGISTER_STATE_SIZE + TRAP_FRAME_SIZE + 8) "), %rsp \n"
|
||||
" cld \n"
|
||||
" call do_init_context \n"
|
||||
" movq %rax, %rsp \n" // move stack pointer to what Processor::init_context set up for us
|
||||
" movq %r12, %rdi \n" // to_thread
|
||||
" movq %r12, %rsi \n" // from_thread
|
||||
" pushq %r12 \n" // to_thread (for thread_context_first_enter)
|
||||
" pushq %r12 \n" // from_thread (for thread_context_first_enter)
|
||||
" leaq thread_context_first_enter(%rip), %r12 \n" // should be same as regs.rip
|
||||
" pushq %r12 \n"
|
||||
" jmp enter_thread_context \n");
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
StringView Processor::platform_string()
|
||||
{
|
||||
return "x86_64"sv;
|
||||
}
|
||||
|
||||
// FIXME: For the most part this is a copy of the i386-specific function, get rid of the code duplication
|
||||
FlatPtr Processor::init_context(Thread& thread, bool leave_crit)
|
||||
{
|
||||
VERIFY(is_kernel_mode());
|
||||
VERIFY(g_scheduler_lock.is_locked());
|
||||
if (leave_crit) {
|
||||
// Leave the critical section we set up in in Process::exec,
|
||||
// but because we still have the scheduler lock we should end up with 1
|
||||
VERIFY(in_critical() == 2);
|
||||
m_in_critical = 1; // leave it without triggering anything or restoring flags
|
||||
}
|
||||
|
||||
u64 kernel_stack_top = thread.kernel_stack_top();
|
||||
|
||||
// Add a random offset between 0-256 (16-byte aligned)
|
||||
kernel_stack_top -= round_up_to_power_of_two(get_fast_random<u8>(), 16);
|
||||
|
||||
u64 stack_top = kernel_stack_top;
|
||||
|
||||
// TODO: handle NT?
|
||||
VERIFY((cpu_flags() & 0x24000) == 0); // Assume !(NT | VM)
|
||||
|
||||
auto& regs = thread.regs();
|
||||
bool return_to_user = (regs.cs & 3) != 0;
|
||||
|
||||
stack_top -= 1 * sizeof(u64);
|
||||
*reinterpret_cast<u64*>(kernel_stack_top - 2 * sizeof(u64)) = FlatPtr(&exit_kernel_thread);
|
||||
|
||||
stack_top -= sizeof(RegisterState);
|
||||
|
||||
// we want to end up 16-byte aligned, %rsp + 8 should be aligned
|
||||
stack_top -= sizeof(u64);
|
||||
*reinterpret_cast<u64*>(kernel_stack_top - sizeof(u64)) = 0;
|
||||
|
||||
// set up the stack so that after returning from thread_context_first_enter()
|
||||
// we will end up either in kernel mode or user mode, depending on how the thread is set up
|
||||
// However, the first step is to always start in kernel mode with thread_context_first_enter
|
||||
RegisterState& iretframe = *reinterpret_cast<RegisterState*>(stack_top);
|
||||
iretframe.rdi = regs.rdi;
|
||||
iretframe.rsi = regs.rsi;
|
||||
iretframe.rbp = regs.rbp;
|
||||
iretframe.rsp = 0;
|
||||
iretframe.rbx = regs.rbx;
|
||||
iretframe.rdx = regs.rdx;
|
||||
iretframe.rcx = regs.rcx;
|
||||
iretframe.rax = regs.rax;
|
||||
iretframe.r8 = regs.r8;
|
||||
iretframe.r9 = regs.r9;
|
||||
iretframe.r10 = regs.r10;
|
||||
iretframe.r11 = regs.r11;
|
||||
iretframe.r12 = regs.r12;
|
||||
iretframe.r13 = regs.r13;
|
||||
iretframe.r14 = regs.r14;
|
||||
iretframe.r15 = regs.r15;
|
||||
iretframe.rflags = regs.rflags;
|
||||
iretframe.rip = regs.rip;
|
||||
iretframe.cs = regs.cs;
|
||||
if (return_to_user) {
|
||||
iretframe.userspace_rsp = regs.rsp;
|
||||
iretframe.userspace_ss = GDT_SELECTOR_DATA3 | 3;
|
||||
} else {
|
||||
iretframe.userspace_rsp = kernel_stack_top;
|
||||
iretframe.userspace_ss = 0;
|
||||
}
|
||||
|
||||
// make space for a trap frame
|
||||
stack_top -= sizeof(TrapFrame);
|
||||
TrapFrame& trap = *reinterpret_cast<TrapFrame*>(stack_top);
|
||||
trap.regs = &iretframe;
|
||||
trap.prev_irq_level = 0;
|
||||
trap.next_trap = nullptr;
|
||||
|
||||
stack_top -= sizeof(u64); // pointer to TrapFrame
|
||||
*reinterpret_cast<u64*>(stack_top) = stack_top + 8;
|
||||
|
||||
if constexpr (CONTEXT_SWITCH_DEBUG) {
|
||||
if (return_to_user) {
|
||||
dbgln("init_context {} ({}) set up to execute at rip={}:{}, rsp={}, stack_top={}, user_top={}",
|
||||
thread,
|
||||
VirtualAddress(&thread),
|
||||
iretframe.cs, regs.rip,
|
||||
VirtualAddress(regs.rsp),
|
||||
VirtualAddress(stack_top),
|
||||
iretframe.userspace_rsp);
|
||||
} else {
|
||||
dbgln("init_context {} ({}) set up to execute at rip={}:{}, rsp={}, stack_top={}",
|
||||
thread,
|
||||
VirtualAddress(&thread),
|
||||
iretframe.cs, regs.rip,
|
||||
VirtualAddress(regs.rsp),
|
||||
VirtualAddress(stack_top));
|
||||
}
|
||||
}
|
||||
|
||||
// make switch_context() always first return to thread_context_first_enter()
|
||||
// in kernel mode, so set up these values so that we end up popping iretframe
|
||||
// off the stack right after the context switch completed, at which point
|
||||
// control is transferred to what iretframe is pointing to.
|
||||
regs.rip = FlatPtr(&thread_context_first_enter);
|
||||
regs.rsp0 = kernel_stack_top;
|
||||
regs.rsp = stack_top;
|
||||
regs.cs = GDT_SELECTOR_CODE0;
|
||||
return stack_top;
|
||||
}
|
||||
|
||||
void Processor::switch_context(Thread*& from_thread, Thread*& to_thread)
|
||||
{
|
||||
VERIFY(!m_in_irq);
|
||||
VERIFY(m_in_critical == 1);
|
||||
VERIFY(is_kernel_mode());
|
||||
|
||||
dbgln_if(CONTEXT_SWITCH_DEBUG, "switch_context --> switching out of: {} {}", VirtualAddress(from_thread), *from_thread);
|
||||
|
||||
// m_in_critical is restored in enter_thread_context
|
||||
from_thread->save_critical(m_in_critical);
|
||||
|
||||
// clang-format off
|
||||
// Switch to new thread context, passing from_thread and to_thread
|
||||
// through to the new context using registers rdx and rax
|
||||
asm volatile(
|
||||
// NOTE: changing how much we push to the stack affects thread_context_first_enter()!
|
||||
"pushfq \n"
|
||||
"pushq %%rbx \n"
|
||||
"pushq %%rcx \n"
|
||||
"pushq %%rbp \n"
|
||||
"pushq %%rsi \n"
|
||||
"pushq %%rdi \n"
|
||||
"pushq %%r8 \n"
|
||||
"pushq %%r9 \n"
|
||||
"pushq %%r10 \n"
|
||||
"pushq %%r11 \n"
|
||||
"pushq %%r12 \n"
|
||||
"pushq %%r13 \n"
|
||||
"pushq %%r14 \n"
|
||||
"pushq %%r15 \n"
|
||||
"movq %%rsp, %[from_rsp] \n"
|
||||
"leaq 1f(%%rip), %%rbx \n"
|
||||
"movq %%rbx, %[from_rip] \n"
|
||||
"movq %[to_rsp0], %%rbx \n"
|
||||
"movl %%ebx, %[tss_rsp0l] \n"
|
||||
"shrq $32, %%rbx \n"
|
||||
"movl %%ebx, %[tss_rsp0h] \n"
|
||||
"movq %[to_rsp], %%rsp \n"
|
||||
"pushq %[to_thread] \n"
|
||||
"pushq %[from_thread] \n"
|
||||
"pushq %[to_rip] \n"
|
||||
"cld \n"
|
||||
"movq 16(%%rsp), %%rsi \n"
|
||||
"movq 8(%%rsp), %%rdi \n"
|
||||
"jmp enter_thread_context \n"
|
||||
"1: \n"
|
||||
"popq %%rdx \n"
|
||||
"popq %%rax \n"
|
||||
"popq %%r15 \n"
|
||||
"popq %%r14 \n"
|
||||
"popq %%r13 \n"
|
||||
"popq %%r12 \n"
|
||||
"popq %%r11 \n"
|
||||
"popq %%r10 \n"
|
||||
"popq %%r9 \n"
|
||||
"popq %%r8 \n"
|
||||
"popq %%rdi \n"
|
||||
"popq %%rsi \n"
|
||||
"popq %%rbp \n"
|
||||
"popq %%rcx \n"
|
||||
"popq %%rbx \n"
|
||||
"popfq \n"
|
||||
: [from_rsp] "=m" (from_thread->regs().rsp),
|
||||
[from_rip] "=m" (from_thread->regs().rip),
|
||||
[tss_rsp0l] "=m" (m_tss.rsp0l),
|
||||
[tss_rsp0h] "=m" (m_tss.rsp0h),
|
||||
"=d" (from_thread), // needed so that from_thread retains the correct value
|
||||
"=a" (to_thread) // needed so that to_thread retains the correct value
|
||||
: [to_rsp] "g" (to_thread->regs().rsp),
|
||||
[to_rsp0] "g" (to_thread->regs().rsp0),
|
||||
[to_rip] "c" (to_thread->regs().rip),
|
||||
[from_thread] "d" (from_thread),
|
||||
[to_thread] "a" (to_thread)
|
||||
: "memory", "rbx"
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
dbgln_if(CONTEXT_SWITCH_DEBUG, "switch_context <-- from {} {} to {} {}", VirtualAddress(from_thread), *from_thread, VirtualAddress(to_thread), *to_thread);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT void Processor::initialize_context_switching(Thread& initial_thread)
|
||||
{
|
||||
VERIFY(initial_thread.process().is_kernel_process());
|
||||
|
||||
auto& regs = initial_thread.regs();
|
||||
m_tss.iomapbase = sizeof(m_tss);
|
||||
m_tss.rsp0l = regs.rsp0 & 0xffffffff;
|
||||
m_tss.rsp0h = regs.rsp0 >> 32;
|
||||
|
||||
m_scheduler_initialized = true;
|
||||
|
||||
// clang-format off
|
||||
asm volatile(
|
||||
"movq %[new_rsp], %%rsp \n" // switch to new stack
|
||||
"pushq %[from_to_thread] \n" // to_thread
|
||||
"pushq %[from_to_thread] \n" // from_thread
|
||||
"pushq %[new_rip] \n" // save the entry rip to the stack
|
||||
"cld \n"
|
||||
"pushq %[cpu] \n" // push argument for init_finished before register is clobbered
|
||||
"call pre_init_finished \n"
|
||||
"pop %%rdi \n" // move argument for init_finished into place
|
||||
"call init_finished \n"
|
||||
"call post_init_finished \n"
|
||||
"movq 24(%%rsp), %%rdi \n" // move pointer to TrapFrame into place
|
||||
"call enter_trap_no_irq \n"
|
||||
"retq \n"
|
||||
:: [new_rsp] "g" (regs.rsp),
|
||||
[new_rip] "a" (regs.rip),
|
||||
[from_to_thread] "b" (&initial_thread),
|
||||
[cpu] "c" ((u64)id())
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
@ -14,11 +14,11 @@
|
||||
#include <Kernel/Arch/DeferredCallEntry.h>
|
||||
#include <Kernel/Arch/PageDirectory.h>
|
||||
#include <Kernel/Arch/ProcessorSpecificDataID.h>
|
||||
#include <Kernel/Arch/x86/ASM_wrapper.h>
|
||||
#include <Kernel/Arch/x86/CPUID.h>
|
||||
#include <Kernel/Arch/x86/DescriptorTable.h>
|
||||
#include <Kernel/Arch/x86/SIMDState.h>
|
||||
#include <Kernel/Arch/x86/TSS.h>
|
||||
#include <Kernel/Arch/x86_64/ASM_wrapper.h>
|
||||
#include <Kernel/Arch/x86_64/CPUID.h>
|
||||
#include <Kernel/Arch/x86_64/DescriptorTable.h>
|
||||
#include <Kernel/Arch/x86_64/SIMDState.h>
|
||||
#include <Kernel/Arch/x86_64/TSS.h>
|
||||
#include <Kernel/Forward.h>
|
||||
#include <Kernel/KString.h>
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/Processor.h>
|
||||
#include <Kernel/Arch/x86/CPUID.h>
|
||||
#include <Kernel/Arch/x86/ProcessorInfo.h>
|
||||
#include <Kernel/Arch/x86_64/CPUID.h>
|
||||
#include <Kernel/Arch/x86_64/ProcessorInfo.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include <AK/Format.h>
|
||||
#include <AK/Time.h>
|
||||
#include <Kernel/Arch/Delay.h>
|
||||
#include <Kernel/Arch/x86/common/CMOS.h>
|
||||
#include <Kernel/Arch/x86/common/RTC.h>
|
||||
#include <Kernel/Arch/x86_64/CMOS.h>
|
||||
#include <Kernel/Arch/x86_64/RTC.h>
|
||||
|
||||
namespace Kernel::RTC {
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <LibC/sys/arch/regs.h>
|
||||
|
||||
#include <Kernel/Arch/CPU.h>
|
||||
#include <Kernel/Arch/x86/ASM_wrapper.h>
|
||||
#include <Kernel/Arch/x86_64/ASM_wrapper.h>
|
||||
|
||||
#include <AK/Platform.h>
|
||||
VALIDATE_IS_X86()
|
@ -4,8 +4,8 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/common/Shutdown.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Arch/x86_64/Shutdown.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <Kernel/Arch/SmapDisabler.h>
|
||||
|
||||
#include <Kernel/Arch/x86/ASM_wrapper.h>
|
||||
#include <Kernel/Arch/x86_64/ASM_wrapper.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/TrapFrame.h>
|
||||
#include <Kernel/Arch/x86/DescriptorTable.h>
|
||||
#include <Kernel/Arch/x86/Processor.h>
|
||||
#include <Kernel/Arch/x86_64/DescriptorTable.h>
|
||||
#include <Kernel/Arch/x86_64/Processor.h>
|
||||
|
||||
extern "C" void syscall_entry();
|
||||
extern "C" [[gnu::naked]] void syscall_entry()
|
@ -4,8 +4,8 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/Time/APICTimer.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86_64/Time/APICTimer.h>
|
||||
#include <Kernel/Panic.h>
|
||||
#include <Kernel/Sections.h>
|
||||
#include <Kernel/Time/TimeManagement.h>
|
@ -7,7 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/x86/common/Interrupts/APIC.h>
|
||||
#include <Kernel/Arch/x86_64/Interrupts/APIC.h>
|
||||
#include <Kernel/Interrupts/GenericInterruptHandler.h>
|
||||
#include <Kernel/Time/HardwareTimer.h>
|
||||
|
@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <AK/StringView.h>
|
||||
#include <Kernel/Arch/x86/Time/HPET.h>
|
||||
#include <Kernel/Arch/x86/Time/HPETComparator.h>
|
||||
#include <Kernel/Arch/x86_64/Time/HPET.h>
|
||||
#include <Kernel/Arch/x86_64/Time/HPETComparator.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/Firmware/ACPI/Parser.h>
|
||||
#include <Kernel/Memory/MemoryManager.h>
|
@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/Time/HPETComparator.h>
|
||||
#include <Kernel/Arch/x86_64/Time/HPETComparator.h>
|
||||
#include <Kernel/Assertions.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/InterruptDisabler.h>
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/x86/Time/HPET.h>
|
||||
#include <Kernel/Arch/x86_64/Time/HPET.h>
|
||||
#include <Kernel/Time/HardwareTimer.h>
|
||||
|
||||
namespace Kernel {
|
@ -4,8 +4,8 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/Time/PIT.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Arch/x86_64/Time/PIT.h>
|
||||
#include <Kernel/InterruptDisabler.h>
|
||||
#include <Kernel/Interrupts/GenericInterruptHandler.h>
|
||||
#include <Kernel/Scheduler.h>
|
@ -4,10 +4,10 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/x86/IO.h>
|
||||
#include <Kernel/Arch/x86/NonMaskableInterruptDisabler.h>
|
||||
#include <Kernel/Arch/x86/Time/RTC.h>
|
||||
#include <Kernel/Arch/x86/common/CMOS.h>
|
||||
#include <Kernel/Arch/x86_64/CMOS.h>
|
||||
#include <Kernel/Arch/x86_64/IO.h>
|
||||
#include <Kernel/Arch/x86_64/NonMaskableInterruptDisabler.h>
|
||||
#include <Kernel/Arch/x86_64/Time/RTC.h>
|
||||
#include <Kernel/InterruptDisabler.h>
|
||||
#include <Kernel/Time/TimeManagement.h>
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Kernel/Arch/x86/common/RTC.h>
|
||||
#include <Kernel/Arch/x86_64/RTC.h>
|
||||
#include <Kernel/Library/NonnullLockRefPtr.h>
|
||||
#include <Kernel/Time/HardwareTimer.h>
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/Processor.h>
|
||||
#include <Kernel/Arch/x86/TrapFrame.h>
|
||||
#include <Kernel/Arch/x86_64/TrapFrame.h>
|
||||
#include <Kernel/InterruptDisabler.h>
|
||||
|
||||
namespace Kernel {
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user