5ed5fddb7c
This commit removes APIs that were previously marked as deprecated. This change has the following implications: - The use of the global 'env()' accessor is not possible anymore. - Boolean accessor methods are no longer prefixed with 'is_'. E.g., instead of 'is_valid()', use 'valid()'. - The last traces of 'Ram_session' are gone now. The 'Env::ram()' accessor returns the 'Ram_allocator' interface, which is a subset of the 'Pd_session' interface. - All connection constructors need the 'Env' as argument. - The 'Reporter' constructor needs an 'Env' argument now because the reporter creates a report connection. - The old overload 'Child_policy::resolve_session_request' that returned a 'Service' does not exist anymore. - The base/printf.h header has been removed, use base/log.h instead. - The old notion of 'Signal_dispatcher' is gone. Use 'Signal_handler'. - Transitional headers like os/server.h, cap_session/, volatile_object.h, os/attached*_dataspace.h, signal_rpc_dispatcher.h have been removed. - The distinction between 'Thread_state' and 'Thread_state_base' does not exist anymore. - The header cpu_thread/capability.h along with the type definition of 'Cpu_thread_capability' has been removed. Use the type 'Thread_capability' define in cpu_session/cpu_session.h instead. - Several XML utilities (i.e., at os/include/decorator) could be removed because their functionality is nowadays covered by util/xml_node.h. - The 'os/ram_session_guard.h' has been removed. Use 'Constrained_ram_allocator' provided by base/ram_allocator.h instead. Issue #1987
206 lines
5.8 KiB
C++
206 lines
5.8 KiB
C++
/*
|
|
* \brief Process creation
|
|
* \author Norman Feske
|
|
* \author Christian Helmuth
|
|
* \date 2006-07-18
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2006-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.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/log.h>
|
|
#include <base/child.h>
|
|
#include <cpu_thread/client.h>
|
|
|
|
/* base-internal includes */
|
|
#include <base/internal/elf.h>
|
|
#include <base/internal/parent_cap.h>
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
Child::Process::Loaded_executable::Loaded_executable(Type type,
|
|
Dataspace_capability ldso_ds,
|
|
Ram_allocator &ram,
|
|
Region_map &local_rm,
|
|
Region_map &remote_rm,
|
|
Parent_capability parent_cap)
|
|
{
|
|
/* skip loading when called during fork */
|
|
if (type == TYPE_FORKED)
|
|
return;
|
|
|
|
/* locally attach ELF binary of the dynamic linker */
|
|
if (!ldso_ds.valid()) {
|
|
error("attempt to start dynamic executable without dynamic linker");
|
|
throw Missing_dynamic_linker();
|
|
}
|
|
|
|
addr_t elf_addr = 0;
|
|
try { elf_addr = local_rm.attach(ldso_ds); }
|
|
catch (Region_map::Invalid_dataspace) {
|
|
error("dynamic linker is an invalid dataspace"); throw; }
|
|
catch (Region_map::Region_conflict) {
|
|
error("region conflict while attaching dynamic linker"); throw; }
|
|
|
|
Elf_binary elf(elf_addr);
|
|
|
|
entry = elf.entry();
|
|
|
|
/* setup region map for the new pd */
|
|
Elf_segment seg;
|
|
|
|
bool parent_info = false;
|
|
|
|
for (unsigned n = 0; (seg = elf.get_segment(n)).valid(); ++n) {
|
|
if (seg.flags().skip) continue;
|
|
if (seg.mem_size() == 0) continue;
|
|
|
|
/* same values for r/o and r/w segments */
|
|
addr_t const addr = (addr_t)seg.start();
|
|
size_t const size = seg.mem_size();
|
|
|
|
bool const write = seg.flags().w;
|
|
bool const exec = seg.flags().x;
|
|
|
|
if (write) {
|
|
|
|
/* read-write segment */
|
|
|
|
/*
|
|
* Note that a failure to allocate a RAM dataspace after other
|
|
* segments were successfully allocated will not revert the
|
|
* previous allocations. The successful allocations will leak.
|
|
* In practice, this is not a problem as each component has its
|
|
* distinct RAM session. When the process creation failed, the
|
|
* entire RAM session will be destroyed and the memory will be
|
|
* regained.
|
|
*/
|
|
|
|
/* alloc dataspace */
|
|
Dataspace_capability ds_cap;
|
|
try { ds_cap = ram.alloc(size); }
|
|
catch (Out_of_ram) {
|
|
error("allocation of read-write segment failed"); throw; };
|
|
|
|
/* attach dataspace */
|
|
void *base;
|
|
try { base = local_rm.attach(ds_cap); }
|
|
catch (Region_map::Invalid_dataspace) {
|
|
error("attempt to attach invalid segment dataspace"); throw; }
|
|
catch (Region_map::Region_conflict) {
|
|
error("region conflict while locally attaching ELF segment"); throw; }
|
|
|
|
void * const ptr = base;
|
|
addr_t const laddr = elf_addr + seg.file_offset();
|
|
|
|
/* copy contents and fill with zeros */
|
|
memcpy(ptr, (void *)laddr, seg.file_size());
|
|
if (size > seg.file_size())
|
|
memset((void *)((addr_t)ptr + seg.file_size()),
|
|
0, size - seg.file_size());
|
|
|
|
/*
|
|
* We store the parent information at the beginning of the first
|
|
* data segment
|
|
*/
|
|
if (!parent_info) {
|
|
*(Untyped_capability::Raw *)ptr = parent_cap.raw();
|
|
parent_info = true;
|
|
}
|
|
|
|
/* detach dataspace */
|
|
local_rm.detach(base);
|
|
|
|
off_t const offset = 0;
|
|
try { remote_rm.attach_at(ds_cap, addr, size, offset); }
|
|
catch (Region_map::Region_conflict) {
|
|
error("region conflict while remotely attaching ELF segment");
|
|
error("addr=", (void *)addr, " size=", (void *)size, " offset=", (void *)offset);
|
|
throw; }
|
|
|
|
} else {
|
|
|
|
/* read-only segment */
|
|
|
|
if (seg.file_size() != seg.mem_size())
|
|
warning("filesz and memsz for read-only segment differ");
|
|
|
|
off_t const offset = seg.file_offset();
|
|
try {
|
|
if (exec)
|
|
remote_rm.attach_executable(ldso_ds, addr, size, offset);
|
|
else
|
|
remote_rm.attach_at(ldso_ds, addr, size, offset);
|
|
}
|
|
catch (Region_map::Region_conflict) {
|
|
error("region conflict while remotely attaching read-only ELF segment");
|
|
error("addr=", (void *)addr, " size=", (void *)size, " offset=", (void *)offset);
|
|
throw;
|
|
}
|
|
catch (Region_map::Invalid_dataspace) {
|
|
error("attempt to attach invalid read-only segment dataspace");
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* detach ELF */
|
|
local_rm.detach((void *)elf_addr);
|
|
}
|
|
|
|
|
|
Child::Initial_thread::Initial_thread(Cpu_session &cpu,
|
|
Pd_session_capability pd,
|
|
Name const &name)
|
|
:
|
|
_cpu(cpu),
|
|
_cap(cpu.create_thread(pd, name, Affinity::Location(), Cpu_session::Weight()))
|
|
{ }
|
|
|
|
|
|
Child::Initial_thread::~Initial_thread()
|
|
{
|
|
_cpu.kill_thread(_cap);
|
|
}
|
|
|
|
|
|
void Child::Initial_thread::start(addr_t ip)
|
|
{
|
|
Cpu_thread_client(_cap).start(ip, 0);
|
|
}
|
|
|
|
|
|
Child::Process::Process(Type type,
|
|
Dataspace_capability ldso_ds,
|
|
Pd_session &pd,
|
|
Initial_thread_base &initial_thread,
|
|
Region_map &local_rm,
|
|
Region_map &remote_rm,
|
|
Parent_capability parent_cap)
|
|
:
|
|
loaded_executable(type, ldso_ds, pd, local_rm, remote_rm, parent_cap)
|
|
{
|
|
/* register parent interface for new protection domain */
|
|
pd.assign_parent(parent_cap);
|
|
|
|
/*
|
|
* Inhibit start of main thread if the new process happens to be forked
|
|
* from another. In this case, the main thread will get manually
|
|
* started after constructing the 'Process'.
|
|
*/
|
|
if (type == TYPE_FORKED)
|
|
return;
|
|
|
|
/* start main thread */
|
|
initial_thread.start(loaded_executable.entry);
|
|
}
|
|
|
|
|
|
Child::Process::~Process() { }
|