class Idt_entry;
-EXTENSION class Thread
+EXTENSION class Thread
{
private:
/**
static Mword exception_cs();
protected:
- Idt_entry *_idt;
- Unsigned16 _idt_limit;
-
static Trap_state::Handler nested_trap_handler FIASCO_FASTCALL;
};
#include "thread.h"
#include "timer.h"
#include "trap_state.h"
-#include "vmem_alloc.h"
Trap_state::Handler Thread::nested_trap_handler FIASCO_FASTCALL;
IMPLEMENT
Thread::Thread()
-: Receiver(&_thread_lock),
+: Receiver(),
Sender(0), // select optimized version of constructor
_pager(Thread_ptr::Invalid),
_exc_handler(Thread_ptr::Invalid),
_del_observer(0)
{
- //assert (current() == thread_lock()->lock_owner());
- assert (state() == Thread_invalid);
+ assert (state(false) == Thread_invalid);
inc_ref();
+ _space.space(Kernel_task::kernel_task());
- if (Config::stack_depth)
+ if (Config::Stack_depth)
std::memset((char*)this + sizeof(Thread), '5',
- Config::thread_block_size-sizeof(Thread)-64);
+ Thread::Size-sizeof(Thread)-64);
_magic = magic;
- _idt_limit = 0;
_recover_jmpbuf = 0;
_timeout = 0;
arch_init();
- state_add_dirty(Thread_dead | Thread_suspended);
+ state_add_dirty(Thread_dead, false);
// ok, we're ready to go!
}
Thread::user_flags() const
{ return regs()->flags(); }
-
-
-PRIVATE inline
-int
-Thread::is_privileged_for_debug(Trap_state * /*ts*/)
-{
-#if 0
- return ((ts->flags() & EFLAGS_IOPL) == EFLAGS_IOPL_U);
-#else
- return 1;
-#endif
-}
-
/** Check if the pagefault occured at a special place: At some places in the
kernel we want to ensure that a specific address is mapped. The regular
case is "mapped", the exception or slow case is "not mapped". The fastest
current_thread()->restore_exc_state();
}
-PRIVATE static
+PRIVATE static
void
Thread::print_page_fault_error(Mword e)
{
PUBLIC
int
Thread::handle_slow_trap(Trap_state *ts)
-{
+{
Address ip;
int from_user = ts->cs() & 3;
if (EXPECT_FALSE(ts->_trapno == 0xee)) //debug IPI
{
- Ipi::eoi(Ipi::Debug);
+ Ipi::eoi(Ipi::Debug, cpu());
goto generic_debug;
}
- if (from_user && (state() & Thread_vcpu_user_mode) && send_exception(ts))
- goto success;
+ if (from_user && _space.user_mode())
+ {
+ if (ts->_trapno == 14 && Kmem::is_io_bitmap_page_fault(ts->_cr2))
+ {
+ ts->_trapno = 13;
+ ts->_err = 0;
+ }
+
+ if (send_exception(ts))
+ goto success;
+ }
// XXX We might be forced to raise an excepton. In this case, our return
// CS:IP points to leave_by_trigger_exception() which will trigger the
if (ts->_trapno == 13 && (ts->_err & 6) == 6)
goto check_exception;
-
- // XXX: need to do in a different way, if on debug stack e.g.
-#if 0
- if (EXPECT_FALSE(!in_context_area((void*)Proc::stack_pointer())))
- goto generic_debug; // we're in the GDB stub or in jdb
- // -- let generic handler handle it
-#endif
-
LOG_TRAP;
if (!check_trap13_kernel (ts))
check_f00f_bug(ts);
// so we were in user mode -- look for something to emulate
-
+
// We continue running with interrupts off -- no sti() here. But
// interrupts may be enabled by the pagefault handler if we get a
// pagefault in peek_user().
// Set up exception handling. If we suffer an un-handled user-space
// page fault, kill the thread.
- jmp_buf pf_recovery;
+ jmp_buf pf_recovery;
unsigned error;
if (EXPECT_FALSE ((error = setjmp(pf_recovery)) != 0) )
{
- WARN ("%p killed:\n"
- "\033[1mUnhandled page fault, code=%08x\033[m\n",
- this, error);
+ WARN("%p killed:\n"
+ "\033[1mUnhandled page fault, code=%08x\033[m\n", this, error);
goto fail_nomsg;
}
_recover_jmpbuf = &pf_recovery;
- switch (handle_io_page_fault(ts, from_user))
+ switch (handle_io_page_fault(ts))
{
case 1: goto success;
case 2: goto fail;
+ default: break;
}
-
- ip = ts->ip();
- // check for "invalid opcode" exception
- if (EXPECT_FALSE (Config::Kip_syscalls && ts->_trapno == 6))
- {
-#if 0
- // Check "lock; nop" opcode
- if (mem_space()->peek ((Unsigned16*) ip, from_user) == 0x90f0)
- {
- ts->consume_instruction(2);
- ts->value(task()->map_kip());
- goto success;
- }
-#endif
- }
+ ip = ts->ip();
// just print out some warning, we do the normal exception handling
handle_sysenter_trap(ts, ip, from_user);
-
- // check for general protection exception
- if (ts->_trapno == 13 && (ts->_err & 0xffff) == 0)
- {
- // find out if we are a privileged task
- bool is_privileged = trap_is_privileged (ts);
-
- // check for "lidt (%eax)"
- if (EXPECT_FALSE
- (ip < Kmem::mem_user_max - 4 &&
- (mem_space()->peek((Mword*) ip, from_user) & 0xffffff) == 0x18010f))
- {
- // emulate "lidt (%eax)"
-
- // read descriptor
- if (ts->value() >= Kmem::mem_user_max - 6)
- goto fail;
-
- Idt_entry *idt
- = mem_space()->peek((Idt_entry**)(ts->value() + 2), from_user);
- Unsigned16 limit = mem_space()->peek ((Unsigned16*) ts->value(), from_user);
-
- if ((Address)idt >= (Address)Kmem::mem_user_max-limit-1)
- goto fail;
-
- // OK; store descriptor
- _idt = idt;
- _idt_limit = (limit + 1) / sizeof(Idt_entry);
-
- // consume instruction and continue
- ts->consume_instruction(3);
- // ignore errors
- goto success;
- }
-
- // check for "wrmsr (%eax)"
- if (EXPECT_FALSE
- (is_privileged
- && (ip < Kmem::mem_user_max - 2)
- && (mem_space()->peek((Unsigned16*) ip, from_user)) == 0x300f
- && (Cpu::cpus.cpu(cpu()).can_wrmsr())))
- {
- printf("Detected wrmsr at %lx\n", ip);
- if (0)
- {
- do_wrmsr_in_kernel (ts);
-
- // consume instruction and continue
- ts->consume_instruction(2);
- // ignore errors
- goto success;
- }
- }
-
- // check for "rdmsr (%eax)"
- if (EXPECT_FALSE
- (is_privileged
- && (ip < Kmem::mem_user_max - 2)
- && (mem_space()->peek((Unsigned16*) ip, from_user)) == 0x320f
- && (Cpu::cpus.cpu(cpu()).can_wrmsr())))
- {
- printf("Detected rdmsr at %lx\n", ip);
- if (0)
- {
- do_rdmsr_in_kernel(ts);
-
- // consume instruction and continue
- ts->consume_instruction(2);
- // ignore errors
- goto success;
- }
- }
- }
_recover_jmpbuf = 0;
check_exception:
if (send_exception(ts))
goto success;
- // let's see if we have a trampoline to invoke
- if (ts->_trapno < 0x20 && ts->_trapno < _idt_limit)
- {
- Idt_entry e = mem_space()->peek(_idt + ts->_trapno, 1);
-
- if ((e.ist() & 0xe0) == 0x00
- && (e.access() & 0x1f) == 0x0f) // gate descriptor ok?
- {
- Address handler = e.offset();
-
- if (handler
- && handler < Kmem::mem_user_max // in user space?
- && ts->sp() <= Kmem::mem_user_max
- && ts->sp() > 5 * sizeof (Mword)) // enough space on user stack?
- {
- // OK, reflect the trap to user mode
- if (1 /* !raise_exception (ts, handler) */)
- {
- // someone interfered and changed our state
- assert (state() & Thread_cancel);
- state_del(Thread_cancel);
- }
-
- goto success; // we've consumed the trap
- }
- }
- }
-
// backward compatibility cruft: check for those insane "int3" debug
// messaging command sequences
- if (ts->_trapno == 3 && is_privileged_for_debug(ts))
+ if (ts->_trapno == 3)
{
if (int3_handler && int3_handler(ts))
goto success;
// privileged tasks also may invoke the kernel debugger with a debug
// exception
- if (ts->_trapno == 1 && is_privileged_for_debug (ts))
+ if (ts->_trapno == 1)
goto generic_debug;
fail:
// can't handle trap -- kill the thread
- WARN ("%p killed:\n"
- "\033[1mUnhandled trap \033[m\n",
- this);
+ WARN("%p killed:\n"
+ "\033[1mUnhandled trap \033[m\n", this);
fail_nomsg:
- if (Config::warn_level >= Warning)
+ if ((int)Config::Warn_level >= Warning)
ts->dump();
- if (Config::conservative)
- kdb_ke("thread killed");
-
halt();
success:
Proc::sti();
// Pagefault in kernel mode and interrupts were disabled
- else
+ else
{
// page fault in kernel memory region
if (Kmem::is_kmem_page_fault(pfa, error_code))
// just not in the currently active page directory)
// Remain cli'd !!!
}
- else if (!Config::conservative &&
- !Kmem::is_kmem_page_fault(pfa, error_code))
+ else if (!Kmem::is_kmem_page_fault(pfa, error_code))
{
// No error -- just enable interrupts.
Proc::sti();
}
- else
+ else
{
- // Error: We interrupted a cli'd kernel context touching kernel space
+ // Error: We interrupted a cli'd kernel context touching kernel space
if (!Thread::log_page_fault())
printf("*P[%lx,%lx,%lx] ", pfa, error_code & 0xffff, ip);
bool
Thread::handle_sigma0_page_fault(Address pfa)
{
- size_t size;
+ Mem_space::Page_order size = mem_space()->largest_page_size(); // take a page size less than 16MB (1<<24)
+ auto f = mem_space()->fitting_sizes();
+ Virt_addr va = Virt_addr(pfa);
// Check if mapping a superpage doesn't exceed the size of physical memory
- if (Cpu::have_superpages()
- // Some distributions do not allow to mmap below a certain threshold
- // (like 64k on Ubuntu 8.04) so we cannot map a superpage at 0 if
- // we're Fiasco-UX
- && (!Config::Is_ux || !(pfa < Config::SUPERPAGE_SIZE)))
- {
- pfa &= Config::SUPERPAGE_MASK;
- size = Config::SUPERPAGE_SIZE;
- }
- else
- {
- pfa &= Config::PAGE_MASK;
- size = Config::PAGE_SIZE;
- }
+ // Some distributions do not allow to mmap below a certain threshold
+ // (like 64k on Ubuntu 8.04) so we cannot map a superpage at 0 if
+ // we're Fiasco-UX
+ while (Config::Is_ux && (va < (Virt_addr(1) << size)))
+ size = f(--size);
+
+ va = cxx::mask_lsb(va, size);
- return mem_space()->v_insert(Mem_space::Phys_addr(pfa), Mem_space::Addr(pfa),
- Mem_space::Size(size),
- Mem_space::Page_writable
- | Mem_space::Page_user_accessible)
+ return mem_space()->v_insert(Mem_space::Phys_addr(va), va, size,
+ Page::Attr(L4_fpage::Rights::URWX()))
!= Mem_space::Insert_err_nomem;
}
-PUBLIC inline
-Utcb *
-Thread::access_utcb() const
-{ return utcb(); }
-
PRIVATE static inline
void
Thread::save_fpu_state_to_utcb(Trap_state *, Utcb *)
}
+//----------------------------------------------------------------------------
+IMPLEMENTATION [(vmx || svm) && (ia32 || amd64)]:
+
+#include "vmx.h"
+#include "svm.h"
+
+IMPLEMENT inline NEEDS["vmx.h", "svm.h"]
+void
+Thread::arch_init_vcpu_state(Vcpu_state *vcpu_state, bool ext)
+{
+ if (!ext)
+ return;
+
+ if (Vmx::cpus.current().vmx_enabled())
+ Vmx::cpus.current().init_vmcs_infos(vcpu_state);
+
+ // currently we do nothing for SVM here
+}
+
//----------------------------------------------------------------------------
IMPLEMENTATION [ia32 || amd64]:
-PRIVATE inline
+PROTECTED inline
void
Thread::vcpu_resume_user_arch()
{}
//----------------------------------------------------------------------------
IMPLEMENTATION [ux]:
-PRIVATE inline
+PROTECTED inline
void
Thread::vcpu_resume_user_arch()
{
}
}
-
//----------------------------------------------------------------------------
IMPLEMENTATION [(ia32,amd64,ux) && !io]:
PRIVATE inline
int
-Thread::handle_io_page_fault(Trap_state *, bool)
+Thread::handle_io_page_fault(Trap_state *)
{ return 0; }
PRIVATE inline
#include "simpleio.h"
#include "static_init.h"
#include "terminate.h"
-#include "utcb_init.h"
int (*Thread::int3_handler)(Trap_state*);
-Per_cpu<Thread::Dbg_stack> DEFINE_PER_CPU Thread::dbg_stack;
+DEFINE_PER_CPU Per_cpu<Thread::Dbg_stack> Thread::dbg_stack;
STATIC_INITIALIZER_P (int3_handler_init, KDB_INIT_PRIO);
// clear out user regs that can be returned from the thread_ex_regs
// system call to prevent covert channel
Entry_frame *r = regs();
- if (Config::enable_io_protection)
- r->flags(EFLAGS_IOPL_K | EFLAGS_IF | 2); // ei
- else
- r->flags(EFLAGS_IOPL_U | EFLAGS_IF | 2); // XXX iopl=kernel
+ r->flags(EFLAGS_IOPL_K | EFLAGS_IF | 2); // ei
r->cs(Gdt::gdt_code_user | Gdt::Selector_user);
r->ss(Gdt::gdt_data_user | Gdt::Selector_user);
r->sp(0);
// after cs initialisation as ip() requires proper cs
r->ip(0);
-
-#ifdef CONFIG_HANDLE_SEGMENTS
- _gs = _fs = Utcb_init::utcb_segment();
-#else
- Cpu::set_gs(Utcb_init::utcb_segment());
- Cpu::set_fs(Utcb_init::utcb_segment());
-#endif
}
int
Thread::handle_int3(Trap_state *ts)
{
- Mem_space *s = current_mem_space();
+ Mem_space *s = current()->mem_space();
int from_user = ts->cs() & 3;
Address ip = ts->ip();
Unsigned8 todo = s->peek((Unsigned8*)ip, from_user);
Mem_space::Status result =
mem_space()->v_insert(
Mem_space::Phys_addr(mem_space()->virt_to_phys_s0((void*)Kmem::io_bitmap_delimiter_page())),
- Mem_space::Addr::create(Mem_layout::Io_bitmap + Mem_layout::Io_port_max / 8),
- Mem_space::Size::create(Config::PAGE_SIZE),
- Pt_entry::global());
+ Virt_addr(Mem_layout::Io_bitmap + Mem_layout::Io_port_max / 8),
+ Mem_space::Page_order(Config::PAGE_SHIFT),
+ Page::Attr(Page::Rights::R(), Page::Type::Normal(), Page::Kern::Global()));
switch (result)
{
return true;
}
-PRIVATE inline
-bool
-Thread::trap_is_privileged(Trap_state *)
-{ return space()->has_io_privileges(); }
-
-PRIVATE inline
-void
-Thread::do_wrmsr_in_kernel(Trap_state *ts)
-{
- // do "wrmsr (msr[ecx], edx:eax)" in kernel
- Cpu::wrmsr (ts->value(), ts->value3(), ts->value2());
-}
-
-PRIVATE inline
-void
-Thread::do_rdmsr_in_kernel(Trap_state *ts)
-{
- // do "rdmsr (msr[ecx], edx:eax)" in kernel
- Unsigned64 msr = Cpu::rdmsr(ts->value2());
- ts->value((Unsigned32) msr);
- ts->value3((Unsigned32) (msr >> 32));
-}
-
PRIVATE inline
int
Thread::handle_not_nested_trap(Trap_state *ts)
{
// no kernel debugger present
- printf(" %p IP="L4_PTR_FMT" Trap=%02lx [Ret/Esc]\n",
+ printf(" %p IP=" L4_PTR_FMT " Trap=%02lx [Ret/Esc]\n",
this, ts->ip(), ts->_trapno);
int r;
// cannot use normal getchar because it may block with hlt and irq's
// are off here
- while ((r=Kconsole::console()->getchar(false)) == -1)
+ while ((r = Kconsole::console()->getchar(false)) == -1)
Proc::pause();
if (r == '\033')
return 0;
}
-PRIVATE inline
+PROTECTED inline
int
Thread::sys_control_arch(Utcb *)
{
return 0;
}
+//---------------------------------------------------------------------------
+IMPLEMENTATION [(ia32 | amd64) & (debug | kdb) & !mp]:
+
+PRIVATE static inline Cpu_number Thread::dbg_find_cpu() { return Cpu_number::boot_cpu(); }
+
+//---------------------------------------------------------------------------
+IMPLEMENTATION [(ia32 | amd64) & (debug | kdb) & mp]:
+
+#include "apic.h"
+
+PRIVATE static inline NEEDS["apic.h"]
+Cpu_number
+Thread::dbg_find_cpu()
+{
+ unsigned long phys_cpu = Apic::get_id();
+ Cpu_number log_cpu = Apic::find_cpu(phys_cpu);
+ if (log_cpu == Cpu_number::nil())
+ {
+ printf("Trap on unknown CPU phys_id=%lx\n", phys_cpu);
+ log_cpu = Cpu_number::boot_cpu();
+ }
+ return log_cpu;
+}
+
//---------------------------------------------------------------------------
IMPLEMENTATION [(ia32 |amd64) & !(debug | kdb)]: