mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 05:27:46 +00:00
Kernel: Rename Thread::tss to Thread::regs and add x86_64 support
We're using software context switches so calling this struct tss is somewhat misleading.
This commit is contained in:
parent
eba33f82b8
commit
f285241cb8
14 changed files with 246 additions and 204 deletions
|
@ -67,6 +67,7 @@ String Processor::platform_string() const
|
|||
return "x86_64";
|
||||
}
|
||||
|
||||
// FIXME: For the most part this is a copy of the i386-specific function, get rid of the code duplication
|
||||
u32 Processor::init_context(Thread& thread, bool leave_crit)
|
||||
{
|
||||
VERIFY(is_kernel_mode());
|
||||
|
@ -88,29 +89,28 @@ u32 Processor::init_context(Thread& thread, bool leave_crit)
|
|||
// TODO: handle NT?
|
||||
VERIFY((cpu_flags() & 0x24000) == 0); // Assume !(NT | VM)
|
||||
|
||||
#if 0
|
||||
auto& tss = thread.tss();
|
||||
bool return_to_user = (tss.cs & 3) != 0;
|
||||
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
|
||||
// userspace_rsp is not popped off by iretq
|
||||
// unless we're switching back to user mode
|
||||
stack_top -= sizeof(RegisterState) - 2 * sizeof(u32);
|
||||
stack_top -= sizeof(RegisterState) - 2 * sizeof(FlatPtr);
|
||||
|
||||
// For kernel threads we'll push the thread function argument
|
||||
// which should be in tss.esp and exit_kernel_thread as return
|
||||
// which should be in regs.rsp and exit_kernel_thread as return
|
||||
// address.
|
||||
stack_top -= 2 * sizeof(u32);
|
||||
*reinterpret_cast<u32*>(kernel_stack_top - 2 * sizeof(u32)) = tss.esp;
|
||||
stack_top -= 2 * sizeof(u64);
|
||||
*reinterpret_cast<u64*>(kernel_stack_top - 2 * sizeof(u32)) = regs.rsp;
|
||||
*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;
|
||||
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
|
||||
|
@ -125,25 +125,24 @@ u32 Processor::init_context(Thread& thread, bool leave_crit)
|
|||
trap.prev_irq_level = 0;
|
||||
trap.next_trap = nullptr;
|
||||
|
||||
stack_top -= sizeof(u32); // pointer to TrapFrame
|
||||
*reinterpret_cast<u32*>(stack_top) = stack_top + 4;
|
||||
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 eip={}:{}, esp={}, stack_top={}, user_top={}:{}",
|
||||
dbgln("init_context {} ({}) set up to execute at rip={}:{}, rsp={}, stack_top={}, user_top={}",
|
||||
thread,
|
||||
VirtualAddress(&thread),
|
||||
iretframe.cs, tss.eip,
|
||||
VirtualAddress(tss.esp),
|
||||
iretframe.cs, regs.rip,
|
||||
VirtualAddress(regs.rsp),
|
||||
VirtualAddress(stack_top),
|
||||
iretframe.userspace_ss,
|
||||
iretframe.userspace_esp);
|
||||
iretframe.userspace_rsp);
|
||||
} else {
|
||||
dbgln("init_context {} ({}) set up to execute at eip={}:{}, esp={}, stack_top={}",
|
||||
dbgln("init_context {} ({}) set up to execute at rip={}:{}, rsp={}, stack_top={}",
|
||||
thread,
|
||||
VirtualAddress(&thread),
|
||||
iretframe.cs, tss.eip,
|
||||
VirtualAddress(tss.esp),
|
||||
iretframe.cs, regs.rip,
|
||||
VirtualAddress(regs.rsp),
|
||||
VirtualAddress(stack_top));
|
||||
}
|
||||
}
|
||||
|
@ -152,18 +151,9 @@ u32 Processor::init_context(Thread& thread, bool leave_crit)
|
|||
// 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.
|
||||
tss.eip = FlatPtr(&thread_context_first_enter);
|
||||
tss.esp0 = kernel_stack_top;
|
||||
tss.esp = stack_top;
|
||||
tss.cs = GDT_SELECTOR_CODE0;
|
||||
tss.ds = GDT_SELECTOR_DATA0;
|
||||
tss.es = GDT_SELECTOR_DATA0;
|
||||
tss.gs = GDT_SELECTOR_DATA0;
|
||||
tss.ss = GDT_SELECTOR_DATA0;
|
||||
tss.fs = GDT_SELECTOR_PROC;
|
||||
#else
|
||||
TODO();
|
||||
#endif
|
||||
regs.rip = FlatPtr(&thread_context_first_enter);
|
||||
regs.rsp0 = kernel_stack_top;
|
||||
regs.rsp = stack_top;
|
||||
return stack_top;
|
||||
}
|
||||
|
||||
|
@ -203,21 +193,40 @@ UNMAP_AFTER_INIT void Processor::initialize_context_switching(Thread& initial_th
|
|||
{
|
||||
VERIFY(initial_thread.process().is_kernel_process());
|
||||
|
||||
auto& tss = initial_thread.tss();
|
||||
m_tss = tss;
|
||||
#if 0
|
||||
m_tss.esp0 = tss.esp0;
|
||||
m_tss.ss0 = GDT_SELECTOR_DATA0;
|
||||
// user mode needs to be able to switch to kernel mode:
|
||||
m_tss.cs = m_tss.ds = m_tss.es = m_tss.gs = m_tss.ss = GDT_SELECTOR_CODE0 | 3;
|
||||
m_tss.fs = GDT_SELECTOR_PROC | 3;
|
||||
#else
|
||||
TODO();
|
||||
#endif
|
||||
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;
|
||||
|
||||
// FIXME: Context switching (see i386 impl)
|
||||
// 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 $" __STRINGIFY(GDT_SELECTOR_CODE0) " \n"
|
||||
"pushq %[new_rip] \n" // save the entry rip to the stack
|
||||
"movq %%rsp, %%rbx \n"
|
||||
"addq $40, %%rbx \n" // calculate pointer to TrapFrame
|
||||
"pushq %%rbx \n"
|
||||
"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"
|
||||
"addq $8, %%rsp \n"
|
||||
"call post_init_finished \n"
|
||||
"pop %%rdi \n" // move pointer to TrapFrame into place
|
||||
"call enter_trap_no_irq \n"
|
||||
"addq $8, %%rsp \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();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue