mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:02: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
				
			
		|  | @ -489,14 +489,10 @@ Vector<FlatPtr> Processor::capture_stack_trace(Thread& thread, size_t max_frames | ||||||
|             // pushed the callee-saved registers, and the last of them happens
 |             // pushed the callee-saved registers, and the last of them happens
 | ||||||
|             // to be ebp.
 |             // to be ebp.
 | ||||||
|             ProcessPagingScope paging_scope(thread.process()); |             ProcessPagingScope paging_scope(thread.process()); | ||||||
|             auto& tss = thread.tss(); |  | ||||||
|             u32* stack_top; |  | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|             stack_top = reinterpret_cast<u32*>(tss.esp); |             auto& regs = thread.regs(); | ||||||
| #else |             u32* stack_top; | ||||||
|             (void)tss; |             stack_top = reinterpret_cast<u32*>(regs.esp); | ||||||
|             TODO(); |  | ||||||
| #endif |  | ||||||
|             if (is_user_range(VirtualAddress(stack_top), sizeof(FlatPtr))) { |             if (is_user_range(VirtualAddress(stack_top), sizeof(FlatPtr))) { | ||||||
|                 if (!copy_from_user(&frame_ptr, &((FlatPtr*)stack_top)[0])) |                 if (!copy_from_user(&frame_ptr, &((FlatPtr*)stack_top)[0])) | ||||||
|                     frame_ptr = 0; |                     frame_ptr = 0; | ||||||
|  | @ -505,8 +501,7 @@ Vector<FlatPtr> Processor::capture_stack_trace(Thread& thread, size_t max_frames | ||||||
|                 if (!safe_memcpy(&frame_ptr, &((FlatPtr*)stack_top)[0], sizeof(FlatPtr), fault_at)) |                 if (!safe_memcpy(&frame_ptr, &((FlatPtr*)stack_top)[0], sizeof(FlatPtr), fault_at)) | ||||||
|                     frame_ptr = 0; |                     frame_ptr = 0; | ||||||
|             } |             } | ||||||
| #if ARCH(I386) |             eip = regs.eip; | ||||||
|             eip = tss.eip; |  | ||||||
| #else | #else | ||||||
|             TODO(); |             TODO(); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -30,8 +30,8 @@ extern "C" void enter_thread_context(Thread* from_thread, Thread* to_thread) | ||||||
|     bool has_fxsr = Processor::current().has_feature(CPUFeature::FXSR); |     bool has_fxsr = Processor::current().has_feature(CPUFeature::FXSR); | ||||||
|     Processor::set_current_thread(*to_thread); |     Processor::set_current_thread(*to_thread); | ||||||
| 
 | 
 | ||||||
|     auto& from_tss = from_thread->tss(); |     auto& from_regs = from_thread->regs(); | ||||||
|     auto& to_tss = to_thread->tss(); |     auto& to_regs = to_thread->regs(); | ||||||
| 
 | 
 | ||||||
|     if (has_fxsr) |     if (has_fxsr) | ||||||
|         asm volatile("fxsave %0" |         asm volatile("fxsave %0" | ||||||
|  | @ -40,10 +40,10 @@ extern "C" void enter_thread_context(Thread* from_thread, Thread* to_thread) | ||||||
|         asm volatile("fnsave %0" |         asm volatile("fnsave %0" | ||||||
|                      : "=m"(from_thread->fpu_state())); |                      : "=m"(from_thread->fpu_state())); | ||||||
| 
 | 
 | ||||||
|     from_tss.fs = get_fs(); |     from_regs.fs = get_fs(); | ||||||
|     from_tss.gs = get_gs(); |     from_regs.gs = get_gs(); | ||||||
|     set_fs(to_tss.fs); |     set_fs(to_regs.fs); | ||||||
|     set_gs(to_tss.gs); |     set_gs(to_regs.gs); | ||||||
| 
 | 
 | ||||||
|     if (from_thread->process().is_traced()) |     if (from_thread->process().is_traced()) | ||||||
|         read_debug_registers_into(from_thread->debug_register_state()); |         read_debug_registers_into(from_thread->debug_register_state()); | ||||||
|  | @ -59,8 +59,8 @@ extern "C" void enter_thread_context(Thread* from_thread, Thread* to_thread) | ||||||
|     tls_descriptor.set_base(to_thread->thread_specific_data()); |     tls_descriptor.set_base(to_thread->thread_specific_data()); | ||||||
|     tls_descriptor.set_limit(to_thread->thread_specific_region_size()); |     tls_descriptor.set_limit(to_thread->thread_specific_region_size()); | ||||||
| 
 | 
 | ||||||
|     if (from_tss.cr3 != to_tss.cr3) |     if (from_regs.cr3 != to_regs.cr3) | ||||||
|         write_cr3(to_tss.cr3); |         write_cr3(to_regs.cr3); | ||||||
| 
 | 
 | ||||||
|     to_thread->set_cpu(processor.get_id()); |     to_thread->set_cpu(processor.get_id()); | ||||||
|     processor.restore_in_critical(to_thread->saved_critical()); |     processor.restore_in_critical(to_thread->saved_critical()); | ||||||
|  | @ -96,7 +96,7 @@ extern "C" void context_first_init([[maybe_unused]] Thread* from_thread, [[maybe | ||||||
| extern "C" u32 do_init_context(Thread* thread, u32 flags) | extern "C" u32 do_init_context(Thread* thread, u32 flags) | ||||||
| { | { | ||||||
|     VERIFY_INTERRUPTS_DISABLED(); |     VERIFY_INTERRUPTS_DISABLED(); | ||||||
|     thread->tss().eflags = flags; |     thread->regs().eflags = flags; | ||||||
|     return Processor::current().init_context(*thread, true); |     return Processor::current().init_context(*thread, true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -54,7 +54,7 @@ asm( | ||||||
| "    movl %eax, %esp \n" // move stack pointer to what Processor::init_context set up for us
 | "    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 to_thread
 | ||||||
| "    pushl %ebx \n" // push from_thread
 | "    pushl %ebx \n" // push from_thread
 | ||||||
| "    pushl $thread_context_first_enter \n" // should be same as tss.eip
 | "    pushl $thread_context_first_enter \n" // should be same as regs.eip
 | ||||||
| "    jmp enter_thread_context \n" | "    jmp enter_thread_context \n" | ||||||
| ); | ); | ||||||
| // clang-format on
 | // clang-format on
 | ||||||
|  | @ -86,8 +86,8 @@ u32 Processor::init_context(Thread& thread, bool leave_crit) | ||||||
|     // TODO: handle NT?
 |     // TODO: handle NT?
 | ||||||
|     VERIFY((cpu_flags() & 0x24000) == 0); // Assume !(NT | VM)
 |     VERIFY((cpu_flags() & 0x24000) == 0); // Assume !(NT | VM)
 | ||||||
| 
 | 
 | ||||||
|     auto& tss = thread.tss(); |     auto& regs = thread.regs(); | ||||||
|     bool return_to_user = (tss.cs & 3) != 0; |     bool return_to_user = (regs.cs & 3) != 0; | ||||||
| 
 | 
 | ||||||
|     // make room for an interrupt frame
 |     // make room for an interrupt frame
 | ||||||
|     if (!return_to_user) { |     if (!return_to_user) { | ||||||
|  | @ -96,10 +96,10 @@ u32 Processor::init_context(Thread& thread, bool leave_crit) | ||||||
|         stack_top -= sizeof(RegisterState) - 2 * sizeof(u32); |         stack_top -= sizeof(RegisterState) - 2 * sizeof(u32); | ||||||
| 
 | 
 | ||||||
|         // For kernel threads we'll push the thread function argument
 |         // 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.esp and exit_kernel_thread as return
 | ||||||
|         // address.
 |         // address.
 | ||||||
|         stack_top -= 2 * sizeof(u32); |         stack_top -= 2 * sizeof(u32); | ||||||
|         *reinterpret_cast<u32*>(kernel_stack_top - 2 * sizeof(u32)) = tss.esp; |         *reinterpret_cast<u32*>(kernel_stack_top - 2 * sizeof(u32)) = regs.esp; | ||||||
|         *reinterpret_cast<u32*>(kernel_stack_top - 3 * sizeof(u32)) = FlatPtr(&exit_kernel_thread); |         *reinterpret_cast<u32*>(kernel_stack_top - 3 * sizeof(u32)) = FlatPtr(&exit_kernel_thread); | ||||||
|     } else { |     } else { | ||||||
|         stack_top -= sizeof(RegisterState); |         stack_top -= sizeof(RegisterState); | ||||||
|  | @ -113,25 +113,25 @@ u32 Processor::init_context(Thread& thread, bool leave_crit) | ||||||
|     // we will end up either in kernel mode or user mode, depending on how the thread is set up
 |     // 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
 |     // However, the first step is to always start in kernel mode with thread_context_first_enter
 | ||||||
|     RegisterState& iretframe = *reinterpret_cast<RegisterState*>(stack_top); |     RegisterState& iretframe = *reinterpret_cast<RegisterState*>(stack_top); | ||||||
|     iretframe.ss = tss.ss; |     iretframe.ss = regs.ss; | ||||||
|     iretframe.gs = tss.gs; |     iretframe.gs = regs.gs; | ||||||
|     iretframe.fs = tss.fs; |     iretframe.fs = regs.fs; | ||||||
|     iretframe.es = tss.es; |     iretframe.es = regs.es; | ||||||
|     iretframe.ds = tss.ds; |     iretframe.ds = regs.ds; | ||||||
|     iretframe.edi = tss.edi; |     iretframe.edi = regs.edi; | ||||||
|     iretframe.esi = tss.esi; |     iretframe.esi = regs.esi; | ||||||
|     iretframe.ebp = tss.ebp; |     iretframe.ebp = regs.ebp; | ||||||
|     iretframe.esp = 0; |     iretframe.esp = 0; | ||||||
|     iretframe.ebx = tss.ebx; |     iretframe.ebx = regs.ebx; | ||||||
|     iretframe.edx = tss.edx; |     iretframe.edx = regs.edx; | ||||||
|     iretframe.ecx = tss.ecx; |     iretframe.ecx = regs.ecx; | ||||||
|     iretframe.eax = tss.eax; |     iretframe.eax = regs.eax; | ||||||
|     iretframe.eflags = tss.eflags; |     iretframe.eflags = regs.eflags; | ||||||
|     iretframe.eip = tss.eip; |     iretframe.eip = regs.eip; | ||||||
|     iretframe.cs = tss.cs; |     iretframe.cs = regs.cs; | ||||||
|     if (return_to_user) { |     if (return_to_user) { | ||||||
|         iretframe.userspace_esp = tss.esp; |         iretframe.userspace_esp = regs.esp; | ||||||
|         iretframe.userspace_ss = tss.ss; |         iretframe.userspace_ss = regs.ss; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // make space for a trap frame
 |     // make space for a trap frame
 | ||||||
|  | @ -149,8 +149,8 @@ u32 Processor::init_context(Thread& thread, bool leave_crit) | ||||||
|             dbgln("init_context {} ({}) set up to execute at eip={}:{}, esp={}, stack_top={}, user_top={}:{}", |             dbgln("init_context {} ({}) set up to execute at eip={}:{}, esp={}, stack_top={}, user_top={}:{}", | ||||||
|                 thread, |                 thread, | ||||||
|                 VirtualAddress(&thread), |                 VirtualAddress(&thread), | ||||||
|                 iretframe.cs, tss.eip, |                 iretframe.cs, regs.eip, | ||||||
|                 VirtualAddress(tss.esp), |                 VirtualAddress(regs.esp), | ||||||
|                 VirtualAddress(stack_top), |                 VirtualAddress(stack_top), | ||||||
|                 iretframe.userspace_ss, |                 iretframe.userspace_ss, | ||||||
|                 iretframe.userspace_esp); |                 iretframe.userspace_esp); | ||||||
|  | @ -158,8 +158,8 @@ u32 Processor::init_context(Thread& thread, bool leave_crit) | ||||||
|             dbgln("init_context {} ({}) set up to execute at eip={}:{}, esp={}, stack_top={}", |             dbgln("init_context {} ({}) set up to execute at eip={}:{}, esp={}, stack_top={}", | ||||||
|                 thread, |                 thread, | ||||||
|                 VirtualAddress(&thread), |                 VirtualAddress(&thread), | ||||||
|                 iretframe.cs, tss.eip, |                 iretframe.cs, regs.eip, | ||||||
|                 VirtualAddress(tss.esp), |                 VirtualAddress(regs.esp), | ||||||
|                 VirtualAddress(stack_top)); |                 VirtualAddress(stack_top)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -168,15 +168,15 @@ u32 Processor::init_context(Thread& thread, bool leave_crit) | ||||||
|     // in kernel mode, so set up these values so that we end up popping iretframe
 |     // 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
 |     // off the stack right after the context switch completed, at which point
 | ||||||
|     // control is transferred to what iretframe is pointing to.
 |     // control is transferred to what iretframe is pointing to.
 | ||||||
|     tss.eip = FlatPtr(&thread_context_first_enter); |     regs.eip = FlatPtr(&thread_context_first_enter); | ||||||
|     tss.esp0 = kernel_stack_top; |     regs.esp0 = kernel_stack_top; | ||||||
|     tss.esp = stack_top; |     regs.esp = stack_top; | ||||||
|     tss.cs = GDT_SELECTOR_CODE0; |     regs.cs = GDT_SELECTOR_CODE0; | ||||||
|     tss.ds = GDT_SELECTOR_DATA0; |     regs.ds = GDT_SELECTOR_DATA0; | ||||||
|     tss.es = GDT_SELECTOR_DATA0; |     regs.es = GDT_SELECTOR_DATA0; | ||||||
|     tss.gs = GDT_SELECTOR_DATA0; |     regs.gs = GDT_SELECTOR_DATA0; | ||||||
|     tss.ss = GDT_SELECTOR_DATA0; |     regs.ss = GDT_SELECTOR_DATA0; | ||||||
|     tss.fs = GDT_SELECTOR_PROC; |     regs.fs = GDT_SELECTOR_PROC; | ||||||
|     return stack_top; |     return stack_top; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -218,14 +218,14 @@ void Processor::switch_context(Thread*& from_thread, Thread*& to_thread) | ||||||
|         "popl %%esi \n" |         "popl %%esi \n" | ||||||
|         "popl %%ebx \n" |         "popl %%ebx \n" | ||||||
|         "popfl \n" |         "popfl \n" | ||||||
|         : [from_esp] "=m" (from_thread->tss().esp), |         : [from_esp] "=m" (from_thread->regs().esp), | ||||||
|           [from_eip] "=m" (from_thread->tss().eip), |           [from_eip] "=m" (from_thread->regs().eip), | ||||||
|           [tss_esp0] "=m" (m_tss.esp0), |           [tss_esp0] "=m" (m_tss.esp0), | ||||||
|           "=d" (from_thread), // needed so that from_thread retains the correct value
 |           "=d" (from_thread), // needed so that from_thread retains the correct value
 | ||||||
|           "=a" (to_thread) // needed so that to_thread retains the correct value
 |           "=a" (to_thread) // needed so that to_thread retains the correct value
 | ||||||
|         : [to_esp] "g" (to_thread->tss().esp), |         : [to_esp] "g" (to_thread->regs().esp), | ||||||
|           [to_esp0] "g" (to_thread->tss().esp0), |           [to_esp0] "g" (to_thread->regs().esp0), | ||||||
|           [to_eip] "c" (to_thread->tss().eip), |           [to_eip] "c" (to_thread->regs().eip), | ||||||
|           [from_thread] "d" (from_thread), |           [from_thread] "d" (from_thread), | ||||||
|           [to_thread] "a" (to_thread) |           [to_thread] "a" (to_thread) | ||||||
|         : "memory" |         : "memory" | ||||||
|  | @ -256,13 +256,10 @@ UNMAP_AFTER_INIT void Processor::initialize_context_switching(Thread& initial_th | ||||||
| { | { | ||||||
|     VERIFY(initial_thread.process().is_kernel_process()); |     VERIFY(initial_thread.process().is_kernel_process()); | ||||||
| 
 | 
 | ||||||
|     auto& tss = initial_thread.tss(); |     auto& regs = initial_thread.regs(); | ||||||
|     m_tss = tss; |     m_tss.iomapbase = sizeof(m_tss); | ||||||
|     m_tss.esp0 = tss.esp0; |     m_tss.esp0 = regs.esp0; | ||||||
|     m_tss.ss0 = GDT_SELECTOR_DATA0; |     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; |  | ||||||
| 
 | 
 | ||||||
|     m_scheduler_initialized = true; |     m_scheduler_initialized = true; | ||||||
| 
 | 
 | ||||||
|  | @ -285,8 +282,8 @@ UNMAP_AFTER_INIT void Processor::initialize_context_switching(Thread& initial_th | ||||||
|         "call enter_trap_no_irq \n" |         "call enter_trap_no_irq \n" | ||||||
|         "addl $4, %%esp \n" |         "addl $4, %%esp \n" | ||||||
|         "lret \n" |         "lret \n" | ||||||
|         :: [new_esp] "g" (tss.esp), |         :: [new_esp] "g" (regs.esp), | ||||||
|            [new_eip] "a" (tss.eip), |            [new_eip] "a" (regs.eip), | ||||||
|            [from_to_thread] "b" (&initial_thread), |            [from_to_thread] "b" (&initial_thread), | ||||||
|            [cpu] "c" (id()) |            [cpu] "c" (id()) | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|  | @ -67,6 +67,7 @@ String Processor::platform_string() const | ||||||
|     return "x86_64"; |     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) | u32 Processor::init_context(Thread& thread, bool leave_crit) | ||||||
| { | { | ||||||
|     VERIFY(is_kernel_mode()); |     VERIFY(is_kernel_mode()); | ||||||
|  | @ -88,29 +89,28 @@ u32 Processor::init_context(Thread& thread, bool leave_crit) | ||||||
|     // TODO: handle NT?
 |     // TODO: handle NT?
 | ||||||
|     VERIFY((cpu_flags() & 0x24000) == 0); // Assume !(NT | VM)
 |     VERIFY((cpu_flags() & 0x24000) == 0); // Assume !(NT | VM)
 | ||||||
| 
 | 
 | ||||||
| #if 0 |     auto& regs = thread.regs(); | ||||||
|     auto& tss = thread.tss(); |     bool return_to_user = (regs.cs & 3) != 0; | ||||||
|     bool return_to_user = (tss.cs & 3) != 0; |  | ||||||
| 
 | 
 | ||||||
|     // make room for an interrupt frame
 |     // make room for an interrupt frame
 | ||||||
|     if (!return_to_user) { |     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
 |         // 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
 |         // 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.
 |         // address.
 | ||||||
|         stack_top -= 2 * sizeof(u32); |         stack_top -= 2 * sizeof(u64); | ||||||
|         *reinterpret_cast<u32*>(kernel_stack_top - 2 * sizeof(u32)) = tss.esp; |         *reinterpret_cast<u64*>(kernel_stack_top - 2 * sizeof(u32)) = regs.rsp; | ||||||
|         *reinterpret_cast<u32*>(kernel_stack_top - 3 * sizeof(u32)) = FlatPtr(&exit_kernel_thread); |         *reinterpret_cast<u32*>(kernel_stack_top - 3 * sizeof(u32)) = FlatPtr(&exit_kernel_thread); | ||||||
|     } else { |     } else { | ||||||
|         stack_top -= sizeof(RegisterState); |         stack_top -= sizeof(RegisterState); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // we want to end up 16-byte aligned, %esp + 4 should be aligned
 |     // we want to end up 16-byte aligned, %esp + 4 should be aligned
 | ||||||
|     stack_top -= sizeof(u32); |     stack_top -= sizeof(u64); | ||||||
|     *reinterpret_cast<u32*>(kernel_stack_top - sizeof(u32)) = 0; |     *reinterpret_cast<u64*>(kernel_stack_top - sizeof(u64)) = 0; | ||||||
| 
 | 
 | ||||||
|     // set up the stack so that after returning from thread_context_first_enter()
 |     // 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
 |     // 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.prev_irq_level = 0; | ||||||
|     trap.next_trap = nullptr; |     trap.next_trap = nullptr; | ||||||
| 
 | 
 | ||||||
|     stack_top -= sizeof(u32); // pointer to TrapFrame
 |     stack_top -= sizeof(u64); // pointer to TrapFrame
 | ||||||
|     *reinterpret_cast<u32*>(stack_top) = stack_top + 4; |     *reinterpret_cast<u64*>(stack_top) = stack_top + 8; | ||||||
| 
 | 
 | ||||||
|     if constexpr (CONTEXT_SWITCH_DEBUG) { |     if constexpr (CONTEXT_SWITCH_DEBUG) { | ||||||
|         if (return_to_user) { |         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, |                 thread, | ||||||
|                 VirtualAddress(&thread), |                 VirtualAddress(&thread), | ||||||
|                 iretframe.cs, tss.eip, |                 iretframe.cs, regs.rip, | ||||||
|                 VirtualAddress(tss.esp), |                 VirtualAddress(regs.rsp), | ||||||
|                 VirtualAddress(stack_top), |                 VirtualAddress(stack_top), | ||||||
|                 iretframe.userspace_ss, |                 iretframe.userspace_rsp); | ||||||
|                 iretframe.userspace_esp); |  | ||||||
|         } else { |         } 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, |                 thread, | ||||||
|                 VirtualAddress(&thread), |                 VirtualAddress(&thread), | ||||||
|                 iretframe.cs, tss.eip, |                 iretframe.cs, regs.rip, | ||||||
|                 VirtualAddress(tss.esp), |                 VirtualAddress(regs.rsp), | ||||||
|                 VirtualAddress(stack_top)); |                 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
 |     // 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
 |     // off the stack right after the context switch completed, at which point
 | ||||||
|     // control is transferred to what iretframe is pointing to.
 |     // control is transferred to what iretframe is pointing to.
 | ||||||
|     tss.eip = FlatPtr(&thread_context_first_enter); |     regs.rip = FlatPtr(&thread_context_first_enter); | ||||||
|     tss.esp0 = kernel_stack_top; |     regs.rsp0 = kernel_stack_top; | ||||||
|     tss.esp = stack_top; |     regs.rsp = 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 |  | ||||||
|     return 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()); |     VERIFY(initial_thread.process().is_kernel_process()); | ||||||
| 
 | 
 | ||||||
|     auto& tss = initial_thread.tss(); |     auto& regs = initial_thread.regs(); | ||||||
|     m_tss = tss; |     m_tss.iomapbase = sizeof(m_tss); | ||||||
| #if 0 |     m_tss.rsp0l = regs.rsp0 & 0xffffffff; | ||||||
|     m_tss.esp0 = tss.esp0; |     m_tss.rsp0h = regs.rsp0 >> 32; | ||||||
|     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 |  | ||||||
| 
 | 
 | ||||||
|     m_scheduler_initialized = true; |     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(); |     VERIFY_NOT_REACHED(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -181,12 +181,11 @@ RefPtr<Process> Process::create_kernel_process(RefPtr<Thread>& first_thread, Str | ||||||
|     if (!first_thread || !process) |     if (!first_thread || !process) | ||||||
|         return {}; |         return {}; | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|     first_thread->tss().eip = (FlatPtr)entry; |     first_thread->regs().eip = (FlatPtr)entry; | ||||||
|     first_thread->tss().esp = FlatPtr(entry_data); // entry function argument is expected to be in tss.esp
 |     first_thread->regs().esp = FlatPtr(entry_data); // entry function argument is expected to be in regs.esp
 | ||||||
| #else | #else | ||||||
|     (void)entry; |     first_thread->regs().rip = (FlatPtr)entry; | ||||||
|     (void)entry_data; |     first_thread->regs().rsp = FlatPtr(entry_data); // entry function argument is expected to be in regs.rsp
 | ||||||
|     PANIC("Process::create_kernel_process() not implemented"); |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     if (process->pid() != 0) { |     if (process->pid() != 0) { | ||||||
|  | @ -645,14 +644,13 @@ RefPtr<Thread> Process::create_kernel_thread(void (*entry)(void*), void* entry_d | ||||||
|     if (!joinable) |     if (!joinable) | ||||||
|         thread->detach(); |         thread->detach(); | ||||||
| 
 | 
 | ||||||
|  |     auto& regs = thread->regs(); | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|     auto& tss = thread->tss(); |     regs.eip = (FlatPtr)entry; | ||||||
|     tss.eip = (FlatPtr)entry; |     regs.esp = FlatPtr(entry_data); // entry function argument is expected to be in regs.rsp
 | ||||||
|     tss.esp = FlatPtr(entry_data); // entry function argument is expected to be in tss.esp
 |  | ||||||
| #else | #else | ||||||
|     (void)entry; |     regs.rip = (FlatPtr)entry; | ||||||
|     (void)entry_data; |     regs.rsp = FlatPtr(entry_data); // entry function argument is expected to be in regs.rsp
 | ||||||
|     PANIC("Process::create_kernel_thread() not implemented"); |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     ScopedSpinLock lock(g_scheduler_lock); |     ScopedSpinLock lock(g_scheduler_lock); | ||||||
|  |  | ||||||
|  | @ -232,7 +232,7 @@ bool Scheduler::pick_next() | ||||||
|         dbgln("Scheduler[{}]: Switch to {} @ {:04x}:{:08x}", |         dbgln("Scheduler[{}]: Switch to {} @ {:04x}:{:08x}", | ||||||
|             Processor::id(), |             Processor::id(), | ||||||
|             thread_to_schedule, |             thread_to_schedule, | ||||||
|             thread_to_schedule.tss().cs, thread_to_schedule.tss().eip); |             thread_to_schedule.regs().cs, thread_to_schedule.regs().eip); | ||||||
| #else | #else | ||||||
|         PANIC("Scheduler::pick_next() not implemented"); |         PANIC("Scheduler::pick_next() not implemented"); | ||||||
| #endif | #endif | ||||||
|  | @ -354,7 +354,8 @@ bool Scheduler::context_switch(Thread* thread) | ||||||
|             from_thread->set_state(Thread::Runnable); |             from_thread->set_state(Thread::Runnable); | ||||||
| 
 | 
 | ||||||
| #ifdef LOG_EVERY_CONTEXT_SWITCH | #ifdef LOG_EVERY_CONTEXT_SWITCH | ||||||
|         dbgln("Scheduler[{}]: {} -> {} [prio={}] {:04x}:{:08x}", Processor::id(), from_thread->tid().value(), thread->tid().value(), thread->priority(), thread->tss().cs, thread->tss().eip); |         dbgln("Scheduler[{}]: {} -> {} [prio={}] {:04x}:{:08x}", Processor::id(), from_thread->tid().value(), | ||||||
|  |             thread->tid().value(), thread->priority(), thread->regs().cs, thread->regs().eip); | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -583,7 +584,7 @@ void dump_thread_list() | ||||||
|     auto get_cs = [](Thread& thread) -> u16 { |     auto get_cs = [](Thread& thread) -> u16 { | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|         if (!thread.current_trap()) |         if (!thread.current_trap()) | ||||||
|             return thread.tss().cs; |             return thread.regs().cs; | ||||||
| #else | #else | ||||||
|         PANIC("get_cs() not implemented"); |         PANIC("get_cs() not implemented"); | ||||||
| #endif | #endif | ||||||
|  | @ -593,7 +594,7 @@ void dump_thread_list() | ||||||
|     auto get_eip = [](Thread& thread) -> u32 { |     auto get_eip = [](Thread& thread) -> u32 { | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|         if (!thread.current_trap()) |         if (!thread.current_trap()) | ||||||
|             return thread.tss().eip; |             return thread.regs().eip; | ||||||
|         return thread.get_register_dump_from_stack().eip; |         return thread.get_register_dump_from_stack().eip; | ||||||
| #else | #else | ||||||
|         PANIC("get_eip() not implemented"); |         PANIC("get_eip() not implemented"); | ||||||
|  |  | ||||||
|  | @ -597,7 +597,7 @@ KResult Process::do_exec(NonnullRefPtr<FileDescription> main_program_description | ||||||
|     auto make_stack_result = make_userspace_stack_for_main_thread(*load_result.stack_region.unsafe_ptr(), move(arguments), move(environment), move(auxv)); |     auto make_stack_result = make_userspace_stack_for_main_thread(*load_result.stack_region.unsafe_ptr(), move(arguments), move(environment), move(auxv)); | ||||||
|     if (make_stack_result.is_error()) |     if (make_stack_result.is_error()) | ||||||
|         return make_stack_result.error(); |         return make_stack_result.error(); | ||||||
|     u32 new_userspace_esp = make_stack_result.value(); |     FlatPtr new_userspace_esp = make_stack_result.value(); | ||||||
| 
 | 
 | ||||||
|     if (wait_for_tracer_at_next_execve()) { |     if (wait_for_tracer_at_next_execve()) { | ||||||
|         // Make sure we release the ptrace lock here or the tracer will block forever.
 |         // Make sure we release the ptrace lock here or the tracer will block forever.
 | ||||||
|  | @ -636,22 +636,21 @@ KResult Process::do_exec(NonnullRefPtr<FileDescription> main_program_description | ||||||
|     } |     } | ||||||
|     new_main_thread->reset_fpu_state(); |     new_main_thread->reset_fpu_state(); | ||||||
| 
 | 
 | ||||||
|  |     auto& regs = new_main_thread->m_regs; | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|     auto& tss = new_main_thread->m_tss; |     regs.cs = GDT_SELECTOR_CODE3 | 3; | ||||||
|     tss.cs = GDT_SELECTOR_CODE3 | 3; |     regs.ds = GDT_SELECTOR_DATA3 | 3; | ||||||
|     tss.ds = GDT_SELECTOR_DATA3 | 3; |     regs.es = GDT_SELECTOR_DATA3 | 3; | ||||||
|     tss.es = GDT_SELECTOR_DATA3 | 3; |     regs.ss = GDT_SELECTOR_DATA3 | 3; | ||||||
|     tss.ss = GDT_SELECTOR_DATA3 | 3; |     regs.fs = GDT_SELECTOR_DATA3 | 3; | ||||||
|     tss.fs = GDT_SELECTOR_DATA3 | 3; |     regs.gs = GDT_SELECTOR_TLS | 3; | ||||||
|     tss.gs = GDT_SELECTOR_TLS | 3; |     regs.eip = load_result.entry_eip; | ||||||
|     tss.eip = load_result.entry_eip; |     regs.esp = new_userspace_esp; | ||||||
|     tss.esp = new_userspace_esp; |  | ||||||
|     tss.cr3 = space().page_directory().cr3(); |  | ||||||
|     tss.ss2 = pid().value(); |  | ||||||
| #else | #else | ||||||
|     (void)new_userspace_esp; |     regs.rip = load_result.entry_eip; | ||||||
|     PANIC("Process::do_exec() not implemented"); |     regs.rsp = new_userspace_esp; | ||||||
| #endif | #endif | ||||||
|  |     regs.cr3 = space().page_directory().cr3(); | ||||||
| 
 | 
 | ||||||
|     { |     { | ||||||
|         TemporaryChange profiling_disabler(m_profiling, was_profiling); |         TemporaryChange profiling_disabler(m_profiling, was_profiling); | ||||||
|  |  | ||||||
|  | @ -45,25 +45,26 @@ KResultOr<pid_t> Process::sys$fork(RegisterState& regs) | ||||||
|     child->space().set_enforces_syscall_regions(space().enforces_syscall_regions()); |     child->space().set_enforces_syscall_regions(space().enforces_syscall_regions()); | ||||||
| 
 | 
 | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|     auto& child_tss = child_first_thread->m_tss; |     auto& child_regs = child_first_thread->m_regs; | ||||||
|     child_tss.eax = 0; // fork() returns 0 in the child :^)
 |     child_regs.eax = 0; // fork() returns 0 in the child :^)
 | ||||||
|     child_tss.ebx = regs.ebx; |     child_regs.ebx = regs.ebx; | ||||||
|     child_tss.ecx = regs.ecx; |     child_regs.ecx = regs.ecx; | ||||||
|     child_tss.edx = regs.edx; |     child_regs.edx = regs.edx; | ||||||
|     child_tss.ebp = regs.ebp; |     child_regs.ebp = regs.ebp; | ||||||
|     child_tss.esp = regs.userspace_esp; |     child_regs.esp = regs.userspace_esp; | ||||||
|     child_tss.esi = regs.esi; |     child_regs.esi = regs.esi; | ||||||
|     child_tss.edi = regs.edi; |     child_regs.edi = regs.edi; | ||||||
|     child_tss.eflags = regs.eflags; |     child_regs.eflags = regs.eflags; | ||||||
|     child_tss.eip = regs.eip; |     child_regs.eip = regs.eip; | ||||||
|     child_tss.cs = regs.cs; |     child_regs.cs = regs.cs; | ||||||
|     child_tss.ds = regs.ds; |     child_regs.ds = regs.ds; | ||||||
|     child_tss.es = regs.es; |     child_regs.es = regs.es; | ||||||
|     child_tss.fs = regs.fs; |     child_regs.fs = regs.fs; | ||||||
|     child_tss.gs = regs.gs; |     child_regs.gs = regs.gs; | ||||||
|     child_tss.ss = regs.userspace_ss; |     child_regs.ss = regs.userspace_ss; | ||||||
| 
 | 
 | ||||||
|     dbgln_if(FORK_DEBUG, "fork: child will begin executing at {:04x}:{:08x} with stack {:04x}:{:08x}, kstack {:04x}:{:08x}", child_tss.cs, child_tss.eip, child_tss.ss, child_tss.esp, child_tss.ss0, child_tss.esp0); |     dbgln_if(FORK_DEBUG, "fork: child will begin executing at {:04x}:{:08x} with stack {:04x}:{:08x}, kstack {:04x}:{:08x}", | ||||||
|  |         child_regs.cs, child_regs.eip, child_regs.ss, child_regs.esp, child_regs.ss0, child_regs.esp0); | ||||||
| #else | #else | ||||||
|     (void)regs; |     (void)regs; | ||||||
|     PANIC("Process::sys$fork() not implemented."); |     PANIC("Process::sys$fork() not implemented."); | ||||||
|  |  | ||||||
|  | @ -61,16 +61,17 @@ KResultOr<int> Process::sys$create_thread(void* (*entry)(void*), Userspace<const | ||||||
|     if (!is_thread_joinable) |     if (!is_thread_joinable) | ||||||
|         thread->detach(); |         thread->detach(); | ||||||
| 
 | 
 | ||||||
|  |     auto& regs = thread->regs(); | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|     auto& tss = thread->tss(); |     regs.eip = (FlatPtr)entry; | ||||||
|     tss.eip = (FlatPtr)entry; |     regs.eflags = 0x0202; | ||||||
|     tss.eflags = 0x0202; |     regs.esp = user_esp.value(); | ||||||
|     tss.cr3 = space().page_directory().cr3(); |  | ||||||
|     tss.esp = user_esp.value(); |  | ||||||
| #else | #else | ||||||
|     (void)entry; |     regs.rip = (FlatPtr)entry; | ||||||
|     PANIC("Process::sys$create_thread() not implemented"); |     regs.rflags = 0x0202; | ||||||
|  |     regs.rsp = user_esp.value(); | ||||||
| #endif | #endif | ||||||
|  |     regs.cr3 = space().page_directory().cr3(); | ||||||
| 
 | 
 | ||||||
|     auto tsr_result = thread->make_thread_specific_region({}); |     auto tsr_result = thread->make_thread_specific_region({}); | ||||||
|     if (tsr_result.is_error()) |     if (tsr_result.is_error()) | ||||||
|  |  | ||||||
|  | @ -84,48 +84,51 @@ Thread::Thread(NonnullRefPtr<Process> process, NonnullOwnPtr<Region> kernel_stac | ||||||
| 
 | 
 | ||||||
|     m_fpu_state = (FPUState*)kmalloc_aligned<16>(sizeof(FPUState)); |     m_fpu_state = (FPUState*)kmalloc_aligned<16>(sizeof(FPUState)); | ||||||
|     reset_fpu_state(); |     reset_fpu_state(); | ||||||
|     m_tss.iomapbase = sizeof(TSS32); |  | ||||||
| 
 | 
 | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|     // Only IF is set when a process boots.
 |     // Only IF is set when a process boots.
 | ||||||
|     m_tss.eflags = 0x0202; |     m_regs.eflags = 0x0202; | ||||||
| 
 | 
 | ||||||
|     if (m_process->is_kernel_process()) { |     if (m_process->is_kernel_process()) { | ||||||
|         m_tss.cs = GDT_SELECTOR_CODE0; |         m_regs.cs = GDT_SELECTOR_CODE0; | ||||||
|         m_tss.ds = GDT_SELECTOR_DATA0; |         m_regs.ds = GDT_SELECTOR_DATA0; | ||||||
|         m_tss.es = GDT_SELECTOR_DATA0; |         m_regs.es = GDT_SELECTOR_DATA0; | ||||||
|         m_tss.fs = GDT_SELECTOR_PROC; |         m_regs.fs = GDT_SELECTOR_PROC; | ||||||
|         m_tss.ss = GDT_SELECTOR_DATA0; |         m_regs.ss = GDT_SELECTOR_DATA0; | ||||||
|         m_tss.gs = 0; |         m_regs.gs = 0; | ||||||
|     } else { |     } else { | ||||||
|         m_tss.cs = GDT_SELECTOR_CODE3 | 3; |         m_regs.cs = GDT_SELECTOR_CODE3 | 3; | ||||||
|         m_tss.ds = GDT_SELECTOR_DATA3 | 3; |         m_regs.ds = GDT_SELECTOR_DATA3 | 3; | ||||||
|         m_tss.es = GDT_SELECTOR_DATA3 | 3; |         m_regs.es = GDT_SELECTOR_DATA3 | 3; | ||||||
|         m_tss.fs = GDT_SELECTOR_DATA3 | 3; |         m_regs.fs = GDT_SELECTOR_DATA3 | 3; | ||||||
|         m_tss.ss = GDT_SELECTOR_DATA3 | 3; |         m_regs.ss = GDT_SELECTOR_DATA3 | 3; | ||||||
|         m_tss.gs = GDT_SELECTOR_TLS | 3; |         m_regs.gs = GDT_SELECTOR_TLS | 3; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     m_tss.cr3 = m_process->space().page_directory().cr3(); |  | ||||||
| #else | #else | ||||||
|     PANIC("Thread::Thread() not implemented"); |     m_regs.rflags = 0x0202; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |     m_regs.cr3 = m_process->space().page_directory().cr3(); | ||||||
|  | 
 | ||||||
|     m_kernel_stack_base = m_kernel_stack_region->vaddr().get(); |     m_kernel_stack_base = m_kernel_stack_region->vaddr().get(); | ||||||
|     m_kernel_stack_top = m_kernel_stack_region->vaddr().offset(default_kernel_stack_size).get() & 0xfffffff8u; |     m_kernel_stack_top = m_kernel_stack_region->vaddr().offset(default_kernel_stack_size).get() & 0xfffffff8u; | ||||||
| 
 | 
 | ||||||
| #if ARCH(I386) |  | ||||||
|     if (m_process->is_kernel_process()) { |     if (m_process->is_kernel_process()) { | ||||||
|         m_tss.esp = m_tss.esp0 = m_kernel_stack_top; | #if ARCH(I386) | ||||||
|  |         m_regs.esp = m_regs.esp0 = m_kernel_stack_top; | ||||||
|  | #else | ||||||
|  |         m_regs.rsp = m_regs.rsp0 = m_kernel_stack_top; | ||||||
|  | #endif | ||||||
|     } else { |     } else { | ||||||
|         // Ring 3 processes get a separate stack for ring 0.
 |         // Ring 3 processes get a separate stack for ring 0.
 | ||||||
|         // The ring 3 stack will be assigned by exec().
 |         // The ring 3 stack will be assigned by exec().
 | ||||||
|         m_tss.ss0 = GDT_SELECTOR_DATA0; | #if ARCH(I386) | ||||||
|         m_tss.esp0 = m_kernel_stack_top; |         m_regs.ss0 = GDT_SELECTOR_DATA0; | ||||||
|     } |         m_regs.esp0 = m_kernel_stack_top; | ||||||
| #else | #else | ||||||
|     PANIC("Thread::Thread() not implemented"); |         m_regs.rsp0 = m_kernel_stack_top; | ||||||
| #endif | #endif | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     // We need to add another reference if we could successfully create
 |     // We need to add another reference if we could successfully create
 | ||||||
|     // all the resources needed for this thread. The reason for this is that
 |     // all the resources needed for this thread. The reason for this is that
 | ||||||
|  | @ -864,9 +867,9 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if ARCH(I386) | #if ARCH(I386) | ||||||
|     dbgln_if(SIGNAL_DEBUG, "Thread in state '{}' has been primed with signal handler {:04x}:{:08x} to deliver {}", state_string(), m_tss.cs, m_tss.eip, signal); |     dbgln_if(SIGNAL_DEBUG, "Thread in state '{}' has been primed with signal handler {:04x}:{:08x} to deliver {}", state_string(), m_regs.cs, m_regs.eip, signal); | ||||||
| #else | #else | ||||||
|     PANIC("Thread:dispatch_signal() not implemented"); |     dbgln_if(SIGNAL_DEBUG, "Thread in state '{}' has been primed with signal handler {:04x}:{:16x} to deliver {}", state_string(), m_regs.cs, m_regs.rip, signal); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     return DispatchSignalResult::Continue; |     return DispatchSignalResult::Continue; | ||||||
|  |  | ||||||
|  | @ -62,6 +62,53 @@ struct ThreadSpecificData { | ||||||
| 
 | 
 | ||||||
| #define THREAD_AFFINITY_DEFAULT 0xffffffff | #define THREAD_AFFINITY_DEFAULT 0xffffffff | ||||||
| 
 | 
 | ||||||
|  | struct ThreadRegisters { | ||||||
|  | #if ARCH(I386) | ||||||
|  |     FlatPtr ss; | ||||||
|  |     FlatPtr gs; | ||||||
|  |     FlatPtr fs; | ||||||
|  |     FlatPtr es; | ||||||
|  |     FlatPtr ds; | ||||||
|  |     FlatPtr edi; | ||||||
|  |     FlatPtr esi; | ||||||
|  |     FlatPtr ebp; | ||||||
|  |     FlatPtr esp; | ||||||
|  |     FlatPtr ebx; | ||||||
|  |     FlatPtr edx; | ||||||
|  |     FlatPtr ecx; | ||||||
|  |     FlatPtr eax; | ||||||
|  |     FlatPtr eip; | ||||||
|  |     FlatPtr esp0; | ||||||
|  |     FlatPtr ss0; | ||||||
|  | #else | ||||||
|  |     FlatPtr rdi; | ||||||
|  |     FlatPtr rsi; | ||||||
|  |     FlatPtr rbp; | ||||||
|  |     FlatPtr rsp; | ||||||
|  |     FlatPtr rbx; | ||||||
|  |     FlatPtr rdx; | ||||||
|  |     FlatPtr rcx; | ||||||
|  |     FlatPtr rax; | ||||||
|  |     FlatPtr r8; | ||||||
|  |     FlatPtr r9; | ||||||
|  |     FlatPtr r10; | ||||||
|  |     FlatPtr r11; | ||||||
|  |     FlatPtr r12; | ||||||
|  |     FlatPtr r13; | ||||||
|  |     FlatPtr r14; | ||||||
|  |     FlatPtr r15; | ||||||
|  |     FlatPtr rip; | ||||||
|  |     FlatPtr rsp0; | ||||||
|  | #endif | ||||||
|  |     FlatPtr cs; | ||||||
|  | #if ARCH(I386) | ||||||
|  |     FlatPtr eflags; | ||||||
|  | #else | ||||||
|  |     FlatPtr rflags; | ||||||
|  | #endif | ||||||
|  |     FlatPtr cr3; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class Thread | class Thread | ||||||
|     : public RefCounted<Thread> |     : public RefCounted<Thread> | ||||||
|     , public Weakable<Thread> { |     , public Weakable<Thread> { | ||||||
|  | @ -748,8 +795,9 @@ public: | ||||||
|     DebugRegisterState& debug_register_state() { return m_debug_register_state; } |     DebugRegisterState& debug_register_state() { return m_debug_register_state; } | ||||||
|     const DebugRegisterState& debug_register_state() const { return m_debug_register_state; } |     const DebugRegisterState& debug_register_state() const { return m_debug_register_state; } | ||||||
| 
 | 
 | ||||||
|     TSS& tss() { return m_tss; } |     ThreadRegisters& regs() { return m_regs; } | ||||||
|     const TSS& tss() const { return m_tss; } |     ThreadRegisters const& regs() const { return m_regs; } | ||||||
|  | 
 | ||||||
|     State state() const { return m_state; } |     State state() const { return m_state; } | ||||||
|     const char* state_string() const; |     const char* state_string() const; | ||||||
| 
 | 
 | ||||||
|  | @ -1210,7 +1258,7 @@ private: | ||||||
|     mutable RecursiveSpinLock m_block_lock; |     mutable RecursiveSpinLock m_block_lock; | ||||||
|     NonnullRefPtr<Process> m_process; |     NonnullRefPtr<Process> m_process; | ||||||
|     ThreadID m_tid { -1 }; |     ThreadID m_tid { -1 }; | ||||||
|     TSS m_tss {}; |     ThreadRegisters m_regs; | ||||||
|     DebugRegisterState m_debug_register_state {}; |     DebugRegisterState m_debug_register_state {}; | ||||||
|     TrapFrame* m_current_trap { nullptr }; |     TrapFrame* m_current_trap { nullptr }; | ||||||
|     u32 m_saved_critical { 1 }; |     u32 m_saved_critical { 1 }; | ||||||
|  |  | ||||||
|  | @ -733,13 +733,8 @@ void MemoryManager::enter_space(Space& space) | ||||||
|     VERIFY(current_thread != nullptr); |     VERIFY(current_thread != nullptr); | ||||||
|     ScopedSpinLock lock(s_mm_lock); |     ScopedSpinLock lock(s_mm_lock); | ||||||
| 
 | 
 | ||||||
| #if ARCH(I386) |     current_thread->regs().cr3 = space.page_directory().cr3(); | ||||||
|     current_thread->tss().cr3 = space.page_directory().cr3(); |  | ||||||
|     write_cr3(space.page_directory().cr3()); |     write_cr3(space.page_directory().cr3()); | ||||||
| #else |  | ||||||
|     (void)space; |  | ||||||
|     PANIC("MemoryManager::enter_space not implemented"); |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MemoryManager::flush_tlb_local(VirtualAddress vaddr, size_t page_count) | void MemoryManager::flush_tlb_local(VirtualAddress vaddr, size_t page_count) | ||||||
|  |  | ||||||
|  | @ -21,11 +21,7 @@ ProcessPagingScope::ProcessPagingScope(Process& process) | ||||||
| ProcessPagingScope::~ProcessPagingScope() | ProcessPagingScope::~ProcessPagingScope() | ||||||
| { | { | ||||||
|     InterruptDisabler disabler; |     InterruptDisabler disabler; | ||||||
| #if ARCH(I386) |     Thread::current()->regs().cr3 = m_previous_cr3; | ||||||
|     Thread::current()->tss().cr3 = m_previous_cr3; |  | ||||||
| #else |  | ||||||
|     PANIC("ProcessPagingScope::~ProcessPagingScope() not implemented"); |  | ||||||
| #endif |  | ||||||
|     write_cr3(m_previous_cr3); |     write_cr3(m_previous_cr3); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -140,7 +140,6 @@ int main(int argc, char** argv) | ||||||
|         u64 arg3 = regs.rbx; |         u64 arg3 = regs.rbx; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         if (ptrace(PT_SYSCALL, g_pid, 0, 0) == -1) { |         if (ptrace(PT_SYSCALL, g_pid, 0, 0) == -1) { | ||||||
|             perror("syscall"); |             perror("syscall"); | ||||||
|             return 1; |             return 1; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gunnar Beutner
						Gunnar Beutner