CPU.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Assertions.h>
  7. #include <AK/Types.h>
  8. #include <Kernel/Arch/x86/CPU.h>
  9. #include <Kernel/Arch/x86/Processor.h>
  10. #include <Kernel/Arch/x86/TrapFrame.h>
  11. #include <Kernel/KSyms.h>
  12. #include <Kernel/Process.h>
  13. #include <Kernel/Thread.h>
  14. namespace Kernel {
  15. // The compiler can't see the calls to these functions inside assembly.
  16. // Declare them, to avoid dead code warnings.
  17. extern "C" void enter_thread_context(Thread* from_thread, Thread* to_thread) __attribute__((used));
  18. extern "C" void context_first_init(Thread* from_thread, Thread* to_thread, TrapFrame* trap) __attribute__((used));
  19. extern "C" u32 do_init_context(Thread* thread, u32 flags) __attribute__((used));
  20. extern "C" void enter_thread_context(Thread* from_thread, Thread* to_thread)
  21. {
  22. VERIFY(from_thread == to_thread || from_thread->state() != Thread::Running);
  23. VERIFY(to_thread->state() == Thread::Running);
  24. bool has_fxsr = Processor::current().has_feature(CPUFeature::FXSR);
  25. Processor::set_current_thread(*to_thread);
  26. auto& from_tss = from_thread->tss();
  27. auto& to_tss = to_thread->tss();
  28. if (has_fxsr)
  29. asm volatile("fxsave %0"
  30. : "=m"(from_thread->fpu_state()));
  31. else
  32. asm volatile("fnsave %0"
  33. : "=m"(from_thread->fpu_state()));
  34. from_tss.fs = get_fs();
  35. from_tss.gs = get_gs();
  36. set_fs(to_tss.fs);
  37. set_gs(to_tss.gs);
  38. if (from_thread->process().is_traced())
  39. read_debug_registers_into(from_thread->debug_register_state());
  40. if (to_thread->process().is_traced()) {
  41. write_debug_registers_from(to_thread->debug_register_state());
  42. } else {
  43. clear_debug_registers();
  44. }
  45. auto& processor = Processor::current();
  46. auto& tls_descriptor = processor.get_gdt_entry(GDT_SELECTOR_TLS);
  47. tls_descriptor.set_base(to_thread->thread_specific_data());
  48. tls_descriptor.set_limit(to_thread->thread_specific_region_size());
  49. if (from_tss.cr3 != to_tss.cr3)
  50. write_cr3(to_tss.cr3);
  51. to_thread->set_cpu(processor.get_id());
  52. processor.restore_in_critical(to_thread->saved_critical());
  53. if (has_fxsr)
  54. asm volatile("fxrstor %0" ::"m"(to_thread->fpu_state()));
  55. else
  56. asm volatile("frstor %0" ::"m"(to_thread->fpu_state()));
  57. // TODO: ioperm?
  58. }
  59. extern "C" void context_first_init([[maybe_unused]] Thread* from_thread, [[maybe_unused]] Thread* to_thread, [[maybe_unused]] TrapFrame* trap)
  60. {
  61. VERIFY(!are_interrupts_enabled());
  62. VERIFY(is_kernel_mode());
  63. dbgln_if(CONTEXT_SWITCH_DEBUG, "switch_context <-- from {} {} to {} {} (context_first_init)", VirtualAddress(from_thread), *from_thread, VirtualAddress(to_thread), *to_thread);
  64. VERIFY(to_thread == Thread::current());
  65. Scheduler::enter_current(*from_thread, true);
  66. // Since we got here and don't have Scheduler::context_switch in the
  67. // call stack (because this is the first time we switched into this
  68. // context), we need to notify the scheduler so that it can release
  69. // the scheduler lock. We don't want to enable interrupts at this point
  70. // as we're still in the middle of a context switch. Doing so could
  71. // trigger a context switch within a context switch, leading to a crash.
  72. Scheduler::leave_on_first_switch(trap->regs->eflags & ~0x200);
  73. }
  74. extern "C" u32 do_init_context(Thread* thread, u32 flags)
  75. {
  76. VERIFY_INTERRUPTS_DISABLED();
  77. thread->tss().eflags = flags;
  78. return Processor::current().init_context(*thread, true);
  79. }
  80. }