FreeNOS
spawn.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <FreeNOS/System.h>
19#include <FileSystemClient.h>
20#include <FileDescriptor.h>
21#include <ExecutableFormat.h>
22#include <Types.h>
23#include <Runtime.h>
24#include "limits.h"
25#include "string.h"
26#include "errno.h"
27#include "unistd.h"
28
29int spawn(Address program, Size programSize, const char *argv[])
30{
31 const FileSystemClient filesystem;
33 ExecutableFormat::Region regions[16];
35 Memory::Range range;
36 uint count = 0;
37 pid_t pid = 0;
38 Size numRegions = 16;
40
41 // Attempt to read executable format
42 if (ExecutableFormat::find((u8 *) program, programSize, &fmt) != ExecutableFormat::Success)
43 {
44 errno = ENOEXEC;
45 return -1;
46 }
47
48 // Find entry point
50 {
51 delete fmt;
52 errno = ENOEXEC;
53 return -1;
54 }
55
56 // Create new process
57 const ulong result = ProcessCtl(ANY, Spawn, entry);
58 if ((result & 0xffff) != API::Success)
59 {
60 delete fmt;
61 errno = EIO;
62 return -1;
63 }
64 pid = (result >> 16);
65
66 // Retrieve memory regions
67 if (fmt->regions(regions, &numRegions) != ExecutableFormat::Success)
68 {
69 delete fmt;
70 errno = ENOEXEC;
71 ProcessCtl(pid, KillPID);
72 return -1;
73 }
74 // Release buffers
75 delete fmt;
76
77 // Map program regions into virtual memory of the new process
78 for (Size i = 0; i < numRegions; i++)
79 {
80 // Setup memory range to copy region data
81 range.virt = regions[i].virt;
82 range.phys = ZERO;
83 range.size = regions[i].memorySize;
84 range.access = regions[i].access;
85
86 // Create mapping first in the new process
87 if (VMCtl(pid, MapContiguous, &range) != API::Success)
88 {
89 errno = EFAULT;
90 ProcessCtl(pid, KillPID);
91 return -1;
92 }
93
94 // Map inside our process
95 range.virt = ZERO;
96 if (VMCtl(SELF, MapContiguous, &range) != API::Success)
97 {
98 errno = EFAULT;
99 ProcessCtl(pid, KillPID);
100 return -1;
101 }
102
103 // Copy data bytes
104 MemoryBlock::copy((void *)range.virt, (const void *)(program + regions[i].dataOffset),
105 regions[i].dataSize);
106
107 // Nulify remaining space
108 if (regions[i].memorySize > regions[i].dataSize)
109 {
110 MemoryBlock::set((void *)(range.virt + regions[i].dataSize), 0,
111 regions[i].memorySize - regions[i].dataSize);
112 }
113
114 // Remove temporary mapping
115 if (VMCtl(SELF, UnMap, &range) != API::Success)
116 {
117 errno = EFAULT;
118 ProcessCtl(pid, KillPID);
119 return -1;
120 }
121 }
122
123 // Create mapping for command-line arguments
124 range = map.range(MemoryMap::UserArgs);
125 range.phys = ZERO;
127 if (VMCtl(pid, MapContiguous, &range) != API::Success)
128 {
129 errno = EFAULT;
130 ProcessCtl(pid, KillPID);
131 return -1;
132 }
133
134 // Allocate arguments and current working directory
135 char *arguments = new char[PAGESIZE*2];
136 memset(arguments, 0, PAGESIZE*2);
137
138 // Fill in arguments
139 while (argv[count] && count < PAGESIZE / ARGV_SIZE)
140 {
141 strlcpy(arguments + (ARGV_SIZE * count), argv[count], ARGV_SIZE);
142 count++;
143 }
144
145 // Fill in the current working directory
146 strlcpy(arguments + PAGESIZE, **filesystem.getCurrentDirectory(), PATH_MAX);
147
148 // Copy argc/argv into the new process
149 if (VMCopy(pid, API::Write, (Address) arguments, range.virt, PAGESIZE * 2) != API::Success)
150 {
151 delete[] arguments;
152 errno = EFAULT;
153 ProcessCtl(pid, KillPID);
154 return -1;
155 }
156
157 // Copy fds into the new process.
158 if (VMCopy(pid, API::Write, (Address) FileDescriptor::instance()->getArray(count),
159 range.virt + (PAGESIZE * 2), range.size - (PAGESIZE * 2)) != API::Success)
160 {
161 delete[] arguments;
162 errno = EFAULT;
163 ProcessCtl(pid, KillPID);
164 return -1;
165 }
166
167 // Let the Child begin execution
168 if (ProcessCtl(pid, Resume) != API::Success)
169 {
170 delete[] arguments;
171 errno = EIO;
172 ProcessCtl(pid, KillPID);
173 return -1;
174 }
175
176 // Done. Cleanup.
177 delete[] arguments;
178 return pid;
179}
u32 entry[]
Definition IntelACPI.h:1
@ Success
Definition API.h:70
@ Write
Definition API.h:99
Memory mapping for the kernel and user processes on the ARM architecture.
Definition ARMMap.h:38
Abstraction class of various executable formats.
virtual Result regions(Region *regions, Size *count) const =0
Memory regions a program needs at runtime.
static Result find(const u8 *image, const Size size, ExecutableFormat **fmt)
Find a ExecutableFormat which can handle the given format.
virtual Result entry(Address *entry) const =0
Lookup the program entry point.
FileSystemClient provides a simple interface to a FileSystemServer.
const String * getCurrentDirectory() const
Get current directory String.
static void * set(void *dest, int ch, unsigned count)
Fill memory with a constant byte.
static Size copy(void *dest, const void *src, Size count)
Copy memory from one place to another.
@ UserArgs
< Used for copying program arguments and file descriptors
Definition MemoryMap.h:61
Memory::Range range(Region region) const
Get memory range for the given region.
Definition MemoryMap.cpp:36
static FileDescriptor * instance()
Retrieve the instance.
Definition Singleton.h:53
API::Result VMCopy(const ProcessID proc, const API::Operation how, const Address ours, const Address theirs, const Size sz)
Prototype for user applications.
Definition VMCopy.h:42
#define SELF
Definition ProcessID.h:35
#define ANY
Definition ProcessID.h:34
API::Result ProcessCtl(const ProcessID proc, const ProcessOperation op, const Address addr=0, const Address output=0)
Prototype for user applications.
Definition ProcessCtl.h:93
API::Result VMCtl(const ProcessID procID, const MemoryOperation op, Memory::Range *range=ZERO)
Prototype for user applications.
Definition VMCtl.h:61
@ UnMap
Definition VMCtl.h:39
@ MapContiguous
Definition VMCtl.h:37
@ Resume
Definition ProcessCtl.h:55
@ Spawn
Definition ProcessCtl.h:39
@ KillPID
Definition ProcessCtl.h:40
#define PAGESIZE
ARM uses 4K pages.
Definition ARMConstant.h:97
C size_t strlcpy(char *dst, const char *src, size_t siz)
Copy src to string dst of size siz.
Definition strlcpy.cpp:19
#define EFAULT
Bad address.
Definition errno.h:106
#define ENOEXEC
Executable file format error.
Definition errno.h:181
C int errno
The lvalue errno is used by many functions to return error values.
C void * memset(void *dest, int ch, size_t count)
Fill memory with a constant byte.
Definition memset.cpp:20
#define EIO
I/O error.
Definition errno.h:130
ProcessID pid_t
Used for process IDs and process group IDs.
Definition types.h:32
int spawn(Address program, Size programSize, const char *argv[])
Create a new process using in-memory image.
Definition spawn.cpp:29
#define PATH_MAX
Maximum file path length.
Definition limits.h:37
#define ARGV_SIZE
Maximum size of each argument.
Definition Runtime.h:33
unsigned long Address
A memory address.
Definition Types.h:131
unsigned long ulong
Unsigned long number.
Definition Types.h:47
unsigned int uint
Unsigned integer number.
Definition Types.h:44
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define ZERO
Zero value.
Definition Macros.h:43
unsigned char u8
Unsigned 8-bit number.
Definition Types.h:59
@ User
Definition Memory.h:44
@ Readable
Definition Memory.h:41
@ Writable
Definition Memory.h:42
Memory range.
Definition Memory.h:56
Size size
Size in number of bytes.
Definition Memory.h:59
Address phys
Physical address.
Definition Memory.h:58
Address virt
Virtual address.
Definition Memory.h:57
Access access
Page access flags.
Definition Memory.h:60