1 using System;
  2 using System.IO;
  3 using System.Collections;
  4 using cmsx.machine;
  5 using cmsx.object;
  6 using cmsx.util;
  7 
  8 namespace cmsx.kernel
  9 {
 10     public SharedPtr<ByteStream> ReadFileIntoMemoryStream(INode* inode)
 11     {
 12         if (Log())
 13         {
 14             LogMessage("proc.exec""read.mem.begin");
 15         }
 16         SharedPtr<ByteStream> memoryStream(new MemoryByteStream());
 17         long fileSize = inode->GetFileSize();
 18         FileSystem* fs = GetMountTable().GetFileSystem(inode->Key().fsNumber);
 19         long bytesLeft = fileSize;
 20         long offset = 0;
 21         while (bytesLeft > 0)
 22         {
 23             int blockNumber = 0;
 24             int blockOffset = 0;
 25             fs->GetBlockManager()->GetBlockNumber(inodeoffsetblockNumberblockOffsetfalse);
 26             long bytesToRead = Min(bytesLeftblockSize - blockOffset);
 27             if (bytesToRead == 0)
 28             {
 29                 break;
 30             }
 31             Block* block = null;
 32             if (!fs->IsRootFileSystem() || blockNumber != 0)
 33             {
 34                 block = fs->GetBlockManager()->ReadBlock(BlockKey(blockNumberinode->Key().fsNumber)null);
 35                 BlockPutter blockPutter(block);
 36                 FileBlock* fileBlock = cast<FileBlock*>(block);
 37                 for (long i = 0; i < bytesToRead; ++i;)
 38                 {
 39                     byte x = fileBlock->GetByte(blockOffset + i);
 40                     memoryStream->Write(x);
 41                 }
 42             }
 43             else
 44             {
 45                 for (long i = 0; i < bytesToRead; ++i;)
 46                 {
 47                     byte x = 0u;
 48                     memoryStream->Write(x);
 49                 }
 50             }
 51             bytesLeft = bytesLeft - bytesToRead;
 52             offset = offset + bytesToRead;
 53         }
 54         if (Log())
 55         {
 56             LogMessage("proc.exec""read.mem.end");
 57         }
 58         return memoryStream;
 59     }
 60 
 61     public SharedPtr<ByteStream> ReadFirstBlockIntoMemoryStream(INode* inode)
 62     {
 63         SharedPtr<ByteStream> memoryStream(new MemoryByteStream());
 64         long fileSize = inode->GetFileSize();
 65         FileSystem* fs = GetMountTable().GetFileSystem(inode->Key().fsNumber);
 66         long bytesLeft = Min(blockSizefileSize);
 67         long offset = 0;
 68         while (bytesLeft > 0)
 69         {
 70             int blockNumber = 0;
 71             int blockOffset = 0;
 72             fs->GetBlockManager()->GetBlockNumber(inodeoffsetblockNumberblockOffsetfalse);
 73             long bytesToRead = Min(bytesLeftblockSize - blockOffset);
 74             if (bytesToRead == 0)
 75             {
 76                 break;
 77             }
 78             Block* block = null;
 79             if (!fs->IsRootFileSystem() || blockNumber != 0)
 80             {
 81                 block = fs->GetBlockManager()->ReadBlock(BlockKey(blockNumberinode->Key().fsNumber)null);
 82                 BlockPutter blockPutter(block);
 83                 FileBlock* fileBlock = cast<FileBlock*>(block);
 84                 for (long i = 0; i < bytesToRead; ++i;)
 85                 {
 86                     byte x = fileBlock->GetByte(blockOffset + i);
 87                     memoryStream->Write(x);
 88                 }
 89             }
 90             else
 91             {
 92                 for (long i = 0; i < bytesToRead; ++i;)
 93                 {
 94                     byte x = 0u;
 95                     memoryStream->Write(x);
 96                 }
 97             }
 98             bytesLeft = bytesLeft - bytesToRead;
 99             offset = offset + bytesToRead;
100         }
101         return memoryStream;
102     }
103 
104     public SharedPtr<ByteStream> ReadFilePortionIntoMemoryStream(INode* inodelong fileOffsetlong count)
105     {
106         SharedPtr<ByteStream> memoryStream(new MemoryByteStream());
107         FileSystem* fs = GetMountTable().GetFileSystem(inode->Key().fsNumber);
108         long offset = fileOffset;
109         while (count > 0)
110         {
111             int blockNumber = 0;
112             int blockOffset = 0;
113             fs->GetBlockManager()->GetBlockNumber(inodeoffsetblockNumberblockOffsetfalse);
114             long bytesLeft = Min(blockSizecount);
115             long bytesToRead = Min(bytesLeftblockSize - blockOffset);
116             if (bytesToRead == 0)
117             {
118                 break;
119             }
120             Block* block = null;
121             if (!fs->IsRootFileSystem() || blockNumber != 0)
122             {
123                 block = fs->GetBlockManager()->ReadBlock(BlockKey(blockNumberinode->Key().fsNumber)null);
124                 BlockPutter blockPutter(block);
125                 FileBlock* fileBlock = cast<FileBlock*>(block);
126                 for (long i = 0; i < bytesToRead; ++i;)
127                 {
128                     byte x = fileBlock->GetByte(blockOffset + i);
129                     memoryStream->Write(x);
130                 }
131             }
132             else
133             {
134                 for (long i = 0; i < bytesToRead; ++i;)
135                 {
136                     byte x = 0u;
137                     memoryStream->Write(x);
138                 }
139             }
140             offset = offset + bytesToRead;
141             count = count - bytesToRead;
142         }
143         return memoryStream;
144     }
145 
146     public void Exec(Machine& machineProcessTable& processTablecmsx.kernel.Process* processint argcint envculong bufferAddresslong count)
147     {
148         if (Log())
149         {
150             LogMessage("proc.exec""begin");
151         }
152         bool followExec = Machine.GetFlag(Machine.Flags.followExec);
153         if (argc < 1)
154         {
155             throw SystemError(EINVAL"exec: argc must be at least 1");
156         }
157         if (envc < 0)
158         {
159             throw SystemError(EINVAL"exec: envc is negative");
160         }
161         if (bufferAddress == 0u)
162         {
163             throw SystemError(EINVAL"exec: buffer address is null");
164         }
165         if (count < 0)
166         {
167             throw SystemError(EINVAL"exec: count is negative");
168         }
169         UniquePtr<byte> buffer(cast<byte*>(RtMemAlloc(count)));
170         ReadProcessMemory(machineprocessbufferAddressbuffer.Get()cast<ulong>(count));
171         MemoryReader reader(buffer.Get()count);
172         List<string> args;
173         for (int i = 0; i < argc; ++i;)
174         {
175             long offset = reader.ReadLong();
176             long length = reader.ReadLong();
177             byte* argPtr = buffer.Get() + offset;
178             MemoryReader argReader(argPtrlength);
179             string arg = argReader.ReadString();
180             if (arg.IsEmpty())
181             {
182                 throw SystemError(EINVAL"exec: argument " + ToString(i) + " is empty");
183             }
184             args.Add(arg);
185         }
186         #assert(!args.IsEmpty());
187         List<string> environment;
188         for (int i = 0; i < envc; ++i;)
189         {
190             long offset = reader.ReadLong();
191             long length = reader.ReadLong();
192             byte* envPtr = buffer.Get() + offset;
193             MemoryReader envReader(envPtrlength);
194             string env = envReader.ReadString();
195             if (env.IsEmpty())
196             {
197                 throw SystemError(EINVAL"exec: environment variable " + ToString(i) + " is empty");
198             }
199             environment.Add(env);
200         }
201         const string& executablePath = args.Front();
202         FileSystem* rootFS = GetMountTable().GetFileSystem(0);
203         INode* inode = rootFS->GetINodeManager()->PathToINode(processexecutablePath);
204         if (inode == null)
205         {
206             throw SystemError(ENOENT"executable '" + executablePath + "' not found");
207         }
208         INodePutter putter(inode);
209         if (inode->Type() != FileType.regular)
210         {
211             throw SystemError(EINVAL"path '" + executablePath + "' does not denote a regular file");
212         }
213         try
214         {
215             inode->CheckPermissions(process->uidprocess->gidAccess.execute);
216         }
217         catch (const Exception& ex)
218         {
219             throw SystemError(EPERM"cannot execute '" + executablePath + "' using uid " + ToString(process->uid) + ": " + ex.Message());
220         }
221         ulong envDataAddress = 0u;
222         Section poolSection = MakePoolSection(argsenvironmentenvDataAddress);
223         long poolDataLength = poolSection.data.Count();
224         long poolSize = Align(poolDataLengthcast<long>(pageSize));
225         ulong poolSegmentSize = cast<ulong>(poolSize);
226         INodeKey executableINodeKey = inode->Key();
227         cmsx.kernel.Process* prevProcess = processTable.GetProcessFromExecutableINodeProcessMap(executableINodeKey);
228         ExecutableFile* executable = null;
229         if (prevProcess != null && !followExec)
230         {
231             if (Log())
232             {
233                 LogMessage("proc.exec""clone.begin");
234             }
235             SharedPtr<ByteStream> memoryStream = ReadFirstBlockIntoMemoryStream(inode);
236             BinaryReader reader(memoryStream);
237             UniquePtr<BinaryFile> binaryFile = ReadBinaryFile(readerexecutablePathReadOption.readHeadersOnly);
238             if (binaryFile.Get() is ExecutableFile*)
239             {
240                 executable = cast<ExecutableFile*>(binaryFile.Get());
241                 FreeProcessMemory(machine.GetMemory()process);
242                 InitializeMemoryTable(machineprocess->memoryTableprevProcess->memoryTablepoolSegmentSize);
243                 AllocateMemory(machine.GetMemory()process->memoryTabletrue);
244                 Section* codeSection = executable->GetCodeSection();
245                 codeSection->SetBaseAddress(4096u);
246                 Section* dataSection = executable->GetDataSection();
247                 SharedPtr<ByteStream> dataSectionMemoryStream = ReadFilePortionIntoMemoryStream(inodecast<long>(dataSection->fileOffset)cast<long>(dataSection->length));
248                 BinaryReader dataSectionReader(dataSectionMemoryStream);
249                 dataSection->Read(dataSectionReader);
250                 WriteProcessMemory(machineprocessdataSection->BaseAddress()dataSection->data.Begin().Ptr()cast<ulong>(dataSection->data.Count())Protection.write);
251                 Section* symbolSection = executable->GetSymbolSection();
252                 SharedPtr<ByteStream> symbolSectionMemoryStream = ReadFilePortionIntoMemoryStream(inodecast<long>(symbolSection->fileOffset)cast<long>(symbolSection->length));
253                 BinaryReader symbolSectionReader(symbolSectionMemoryStream);
254                 symbolSection->Read(symbolSectionReader);
255                 executable->AddSymbolsToAddressMap();
256                 Symbol* mainFunctionSymbol = executable->GetSymbolTable().GetSymbol("Main");
257                 process->entryPoint = mainFunctionSymbol->start;
258                 SaveContext(machineprocess);
259                 Symbol* functionTableSymbol = executable->GetSymbolTable().GetSymbol("@function_table");
260                 process->functionTableAddress = functionTableSymbol->start;
261                 process->functionTableLength = functionTableSymbol->length;
262                 if (followExec)
263                 {
264                     executable = cast<ExecutableFile*>(binaryFile.Release());
265                 }
266             }
267             else
268             {
269                 throw SystemError(EINVAL"file '" + executablePath + "' is not a CMSX executable");
270             }
271             if (Log())
272             {
273                 LogMessage("proc.exec""clone.end");
274             }
275         }
276         else
277         {
278             if (Log())
279             {
280                 LogMessage("proc.exec""read.begin");
281             }
282             SharedPtr<ByteStream> memoryStream = ReadFileIntoMemoryStream(inode);
283             BinaryReader reader(memoryStream);
284             UniquePtr<BinaryFile> binaryFile = ReadBinaryFile(readerexecutablePath);
285             if (binaryFile.Get() is ExecutableFile*)
286             {
287                 executable = cast<ExecutableFile*>(binaryFile.Get());
288                 executable->AddSymbolsToAddressMap();
289                 Section* codeSection = executable->GetCodeSection();
290                 Section* dataSection = executable->GetDataSection();
291                 Section* symbolSection = executable->GetSymbolSection();
292                 Symbol* mainFunctionSymbol = executable->GetSymbolTable().GetSymbol("Main");
293                 process->entryPoint = mainFunctionSymbol->start;
294                 ulong textSegmentStartAddress = codeSection->BaseAddress();
295                 if (textSegmentStartAddress == 0u)
296                 {
297                     textSegmentStartAddress = textSegmentStartAddress + 4096u;
298                 }
299                 ulong textSegmentSize = codeSection->DataLength();
300                 ulong dataSegmentSize = dataSection->DataLength();
301                 ulong minStackSegmentSize = cast<ulong>(executable->MinStackSize());
302                 ulong maxStackSegmentSize = cast<ulong>(executable->MaxStackSize());
303                 ulong stackSegmentIncrement = cast<ulong>(executable->StackSizeIncrement());
304                 FreeProcessMemory(machine.GetMemory()process);
305                 InitializeProcessMemory(machineprocesstextSegmentStartAddresstextSegmentSizedataSegmentSizepoolSegmentSizeminStackSegmentSizemaxStackSegmentSizestackSegmentIncrement);
306                 if (codeSection->length > 0u)
307                 {
308                     WriteProcessMemory(machineprocesscodeSection->BaseAddress()codeSection->data.Begin().Ptr()cast<ulong>(codeSection->data.Count())Protection.execute);
309                 }
310                 if (dataSection->length > 0u)
311                 {
312                     WriteProcessMemory(machineprocessdataSection->BaseAddress()dataSection->data.Begin().Ptr()cast<ulong>(dataSection->data.Count())Protection.write);
313                 }
314                 Symbol* functionTableSymbol = executable->GetSymbolTable().GetSymbol("@function_table");
315                 process->functionTableAddress = functionTableSymbol->start;
316                 process->functionTableLength = functionTableSymbol->length;
317                 if (followExec)
318                 {
319                     executable = cast<ExecutableFile*>(binaryFile.Release());
320                 }
321             }
322             else
323             {
324                 throw SystemError(EINVAL"file '" + executablePath + "' is not a CMSX executable");
325             }
326             if (Log())
327             {
328                 LogMessage("proc.exec""read.end");
329             }
330         }
331         process->executableINodeKey = executableINodeKey;
332         processTable.AddProcessToExecutableINodeProcessMap(process);
333         ulong poolStart = poolSegmentBaseAddress + cast<ulong>(poolSize);
334         ulong poolEnd = poolSegmentBaseAddress + cast<ulong>(poolSize);
335         process->poolStart = poolStart;
336         process->poolEnd = poolEnd;
337         process->name = Path.GetFileName(executablePath);
338         if (!poolSection.data.IsEmpty())
339         {
340             WriteProcessMemory(machineprocesspoolSegmentBaseAddresspoolSection.data.Begin().Ptr()cast<ulong>(poolSection.data.Count())Protection.write);
341             int ax = cast<int>(args.Count());
342             ulong bx = poolSegmentBaseAddress;
343             ulong cx = envDataAddress;
344             WriteProcessMemory(machineprocessprocess->regAXAddresscast<ulong>(ax)8uProtection.write);
345             WriteProcessMemory(machineprocessprocess->regBXAddressbx8uProtection.write);
346             WriteProcessMemory(machineprocessprocess->regCXAddresscx8uProtection.write);
347         }
348         if (Log())
349         {
350             LogMessage("proc.exec""ready");
351         }
352         SetProcessReadyToRun(processTableprocess);
353         process->unsave = true;
354         if (followExec)
355         {
356             Kernel& kernel = GetKernel();
357             kernel.SetExecutable(executable);
358             Debugger* debugger = kernel.GetDebugger();
359             debugger->Init(process);
360         }
361         if (Log())
362         {
363             LogMessage("proc.exec""schedule");
364         }
365         Schedule(machineprocessTable);
366         if (Log())
367         {
368             LogMessage("proc.exec""end");
369         }
370     }
371 }