-
Notifications
You must be signed in to change notification settings - Fork 57
/
elf_loader.cpp
175 lines (147 loc) · 6.26 KB
/
elf_loader.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Ghost, a micro-kernel based operating system for the x86 architecture *
* Copyright (C) 2015, Max Schlüssel <lokoxe@gmail.com> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "kernel/tasking/elf/elf_loader.hpp"
#include "kernel/calls/syscall.hpp"
#include "kernel/filesystem/filesystem.hpp"
#include "kernel/memory/memory.hpp"
#include "kernel/tasking/elf/elf_tls.hpp"
#include "kernel/tasking/tasking_memory.hpp"
#include "shared/utils/string.hpp"
g_load_executable_result elfLoadExecutable(g_fd fd, g_security_level securityLevel)
{
g_load_executable_result res;
g_process* process = taskingGetCurrentTask()->process;
if(process->object)
{
logInfo("%! attempted to load two executables in the same address space", "elf");
res.status = G_SPAWN_STATUS_MEMORY_ERROR;
return res;
}
auto rootRes = elfObjectLoad(nullptr, "root", fd, 0);
res.status = rootRes.status;
res.validationDetails = rootRes.validation;
if(rootRes.status == G_SPAWN_STATUS_SUCCESSFUL)
{
elfTlsCreateMasterImage(fd, process, rootRes.object);
g_address imageEnd = elfUserProcessCreateInfo(process, rootRes.object, rootRes.nextFreeBase, securityLevel);
process->object = rootRes.object;
process->image.start = rootRes.object->startAddress;
process->image.end = imageEnd;
res.entry = rootRes.object->header.e_entry;
}
return res;
}
g_virtual_address elfUserProcessCreateInfo(g_process* process, g_elf_object* rootObject, g_virtual_address imageEnd, g_security_level securityLevel)
{
// Calculate required space
int objectCount = 0;
uint32_t stringTableSize = 0;
auto it = hashmapIteratorStart(rootObject->loadedObjects);
while(hashmapIteratorHasNext(&it))
{
auto object = hashmapIteratorNext(&it)->value;
stringTableSize += stringLength(object->name) + 1;
objectCount++;
}
hashmapIteratorEnd(&it);
uint32_t totalRequired = sizeof(g_process_info) + sizeof(g_object_info) * objectCount + stringTableSize;
// Map required memory all loaded objects
uint32_t areaStart = imageEnd;
uint32_t pages = G_PAGE_ALIGN_UP(totalRequired) / G_PAGE_SIZE;
for(uint32_t i = 0; i < pages; i++)
{
g_physical_address page = memoryPhysicalAllocate();
pagingMapPage(areaStart + i * G_PAGE_SIZE, page, DEFAULT_USER_TABLE_FLAGS, DEFAULT_USER_PAGE_FLAGS);
}
// Fill with data
g_process_info* info = (g_process_info*) areaStart;
g_object_info* objectInfo = (g_object_info*) (areaStart + sizeof(g_process_info));
char* stringTable = (char*) ((g_virtual_address) objectInfo + (sizeof(g_object_info) * objectCount));
memorySetBytes((void*) info, 0, sizeof(g_process_info));
info->objectInfosSize = objectCount;
info->objectInfos = objectInfo;
it = hashmapIteratorStart(rootObject->loadedObjects);
while(hashmapIteratorHasNext(&it))
{
g_elf_object* object = hashmapIteratorNext(&it)->value;
memorySetBytes((void*) objectInfo, 0, sizeof(g_object_info));
objectInfo->name = stringTable;
stringCopy(stringTable, object->name);
stringTable += stringLength(object->name) + 1;
objectInfo->preinitArray = object->preinitArray;
objectInfo->preinitArraySize = object->preinitArraySize;
objectInfo->init = object->init;
objectInfo->initArray = object->initArray;
objectInfo->initArraySize = object->initArraySize;
objectInfo->fini = object->fini;
objectInfo->finiArray = object->finiArray;
objectInfo->finiArraySize = object->finiArraySize;
objectInfo++;
}
hashmapIteratorEnd(&it);
info->syscallKernelEntry = syscall;
process->userProcessInfo = info;
return imageEnd + G_PAGE_ALIGN_UP(totalRequired);
}
g_spawn_validation_details elfReadAndValidateHeader(g_fd file, Elf32_Ehdr* headerBuffer, bool root)
{
if(!filesystemReadToMemory(file, 0, (uint8_t*) headerBuffer, sizeof(Elf32_Ehdr)))
{
logInfo("%! failed to spawn file %i due to io error", "elf", file);
return G_SPAWN_VALIDATION_ELF32_IO_ERROR;
}
return elfValidateHeader(headerBuffer, root);
}
g_spawn_validation_details elfValidateHeader(Elf32_Ehdr* header, bool root)
{
if((header->e_ident[EI_MAG0] != ELFMAG0) || // 0x7F
(header->e_ident[EI_MAG1] != ELFMAG1) || // E
(header->e_ident[EI_MAG2] != ELFMAG2) || // L
(header->e_ident[EI_MAG3] != ELFMAG3)) // F
{
return G_SPAWN_VALIDATION_ELF32_NOT_ELF;
}
// Check executable flag
if(root && header->e_type != ET_EXEC)
{
return G_SPAWN_VALIDATION_ELF32_NOT_EXECUTABLE;
}
// Must be i386 architecture compatible
if(header->e_machine != EM_386)
{
return G_SPAWN_VALIDATION_ELF32_NOT_I386;
}
// Must be 32 bit
if(header->e_ident[EI_CLASS] != ELFCLASS32)
{
return G_SPAWN_VALIDATION_ELF32_NOT_32BIT;
}
// Must be little endian
if(header->e_ident[EI_DATA] != ELFDATA2LSB)
{
return G_SPAWN_VALIDATION_ELF32_NOT_LITTLE_ENDIAN;
}
// Must comply to current ELF standard
if(header->e_version != EV_CURRENT)
{
return G_SPAWN_VALIDATION_ELF32_NOT_STANDARD_ELF;
}
return G_SPAWN_VALIDATION_SUCCESSFUL;
}