/* * \brief Thread facility * \author Martin Stein * \author Stefan Kalkowski * \date 2012-02-12 */ /* * Copyright (C) 2012-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ /* core includes */ #include #include #include #include #include /* base-internal includes */ #include #include /* kernel includes */ #include #include using namespace Genode; void Platform_thread::_init() { } Weak_ptr& Platform_thread::address_space() { return _address_space; } Platform_thread::~Platform_thread() { /* detach UTCB of main threads */ if (_main_thread) { Locked_ptr locked_ptr(_address_space); if (locked_ptr.valid()) locked_ptr->flush((addr_t)_utcb_pd_addr, sizeof(Native_utcb), Address_space::Core_local_addr{0}); } /* free UTCB */ core_env()->ram_session()->free(_utcb); } void Platform_thread::quota(size_t const quota) { Kernel::thread_quota(kernel_object(), quota); } Platform_thread::Platform_thread(const char * const label, Native_utcb * utcb) : Kernel_object(true, Kernel::Cpu_priority::MAX, 0, _label), _pd(Kernel::core_pd()->platform_pd()), _pager(nullptr), _utcb_core_addr(utcb), _utcb_pd_addr(utcb), _main_thread(false) { strncpy(_label, label, LABEL_MAX_LEN); /* create UTCB for a core thread */ void *utcb_phys; if (!platform()->ram_alloc()->alloc(sizeof(Native_utcb), &utcb_phys)) { error("failed to allocate UTCB"); throw Out_of_ram(); } map_local((addr_t)utcb_phys, (addr_t)_utcb_core_addr, sizeof(Native_utcb) / get_page_size()); } Platform_thread::Platform_thread(size_t const quota, const char * const label, unsigned const virt_prio, Affinity::Location location, addr_t const utcb) : Kernel_object(true, _priority(virt_prio), quota, _label), _pd(nullptr), _pager(nullptr), _utcb_pd_addr((Native_utcb *)utcb), _main_thread(false) { strncpy(_label, label, LABEL_MAX_LEN); try { _utcb = core_env()->ram_session()->alloc(sizeof(Native_utcb), CACHED); } catch (...) { error("failed to allocate UTCB"); throw Out_of_ram(); } _utcb_core_addr = (Native_utcb *)core_env()->rm_session()->attach(_utcb); affinity(location); } void Platform_thread::join_pd(Platform_pd * pd, bool const main_thread, Weak_ptr address_space) { /* check if thread is already in another protection domain */ if (_pd && _pd != pd) { error("thread already in another protection domain"); return; } /* join protection domain */ _pd = pd; _main_thread = main_thread; _address_space = address_space; } void Platform_thread::affinity(Affinity::Location const & location) { _location = location; } Affinity::Location Platform_thread::affinity() const { return _location; } int Platform_thread::start(void * const ip, void * const sp) { /* attach UTCB in case of a main thread */ if (_main_thread) { /* lookup dataspace component for physical address */ auto lambda = [&] (Dataspace_component *dsc) { if (!dsc) return -1; /* lock the address space */ Locked_ptr locked_ptr(_address_space); if (!locked_ptr.valid()) { error("invalid RM client"); return -1; }; _utcb_pd_addr = (Native_utcb *)user_utcb_main_thread(); Hw::Address_space * as = static_cast(&*locked_ptr); if (!as->insert_translation((addr_t)_utcb_pd_addr, dsc->phys_addr(), sizeof(Native_utcb), Hw::PAGE_FLAGS_UTCB)) { error("failed to attach UTCB"); return -1; } return 0; }; if (core_env()->entrypoint()->apply(_utcb, lambda)) return -1; } /* initialize thread registers */ kernel_object()->ip = reinterpret_cast(ip); kernel_object()->sp = reinterpret_cast(sp); /* start executing new thread */ if (!_pd) { error("no protection domain associated!"); return -1; } unsigned const cpu = _location.valid() ? _location.xpos() : Cpu::primary_id(); Native_utcb * utcb = Thread::myself()->utcb(); /* reset capability counter */ utcb->cap_cnt(0); utcb->cap_add(Capability_space::capid(_cap)); if (_main_thread) { utcb->cap_add(Capability_space::capid(_pd->parent())); utcb->cap_add(Capability_space::capid(_utcb)); } Kernel::start_thread(kernel_object(), cpu, &_pd->kernel_pd(), _utcb_core_addr); return 0; } void Platform_thread::pager(Pager_object * const pager) { using namespace Kernel; thread_pager(kernel_object(), pager ? Capability_space::capid(pager->cap()) : cap_id_invalid()); _pager = pager; } Genode::Pager_object * Platform_thread::pager() { return _pager; } Thread_state Platform_thread::state() { Thread_state_base bstate(*kernel_object()); return Thread_state(bstate); } void Platform_thread::state(Thread_state thread_state) { Cpu_state * cstate = static_cast(kernel_object()); *cstate = static_cast(thread_state); } void Platform_thread::restart() { Kernel::restart_thread(Capability_space::capid(_cap)); }