Loading [MathJax]/extensions/tex2jax.js
CS350 COS
COS
All Data Structures Files Functions Variables Typedefs Macros
loader.c File Reference
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/kassert.h>
#include <sys/sysctl.h>
#include <sys/kmem.h>
#include <sys/queue.h>
#include <sys/disk.h>
#include <sys/elf64.h>
#include <machine/amd64.h>
#include <machine/trap.h>
#include <machine/pmap.h>
#include <sys/thread.h>
#include <sys/spinlock.h>
#include <sys/loader.h>
#include <sys/vfs.h>
Include dependency graph for loader.c:

Go to the source code of this file.

Functions

HandleConsole_OpenHandle ()
 
bool Loader_CheckHeader (const Elf64_Ehdr *ehdr)
 
static void LoaderLoadSegment (AS *as, VNode *vn, uintptr_t vaddr, uintptr_t offset, uintptr_t len)
 
static void LoaderZeroSegment (AS *as, uintptr_t vaddr, uintptr_t len)
 
bool Loader_Load (Thread *thr, VNode *vn, void *buf, uint64_t len)
 
void Loader_LoadInit ()
 

Function Documentation

◆ Console_OpenHandle()

Handle * Console_OpenHandle ( )

Definition at line 200 of file console.c.

201{
202 Handle *handle = Handle_Alloc();
203 if (!handle)
204 return NULL;
205
206 handle->read = &Console_Read;
207 handle->write = &Console_Write;
208 handle->flush = &Console_Flush;
209 handle->close = &Console_Close;
210
211 return handle;
212}
int Console_Close(Handle *handle)
Definition: console.c:193
int Console_Write(Handle *handle, void *buf, uint64_t off, uint64_t len)
Definition: console.c:167
int Console_Read(Handle *handle, void *buf, uint64_t off, uint64_t len)
Definition: console.c:151
int Console_Flush(Handle *handle)
Definition: console.c:187
#define NULL
Definition: stddef.h:6
Definition: handle.h:17
int(* close)(Handle *)
Definition: handle.h:26
int(* write)(Handle *, void *, uint64_t, uint64_t)
Definition: handle.h:24
int(* read)(Handle *, void *, uint64_t, uint64_t)
Definition: handle.h:23
int(* flush)(Handle *)
Definition: handle.h:25
Here is the caller graph for this function:

◆ Loader_CheckHeader()

bool Loader_CheckHeader ( const Elf64_Ehdr ehdr)

Loader_CheckHeader –

Check that the program has a valid ELF header.

Definition at line 34 of file loader.c.

35{
36 if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
37 ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
38 ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
39 ehdr->e_ident[EI_MAG3] != ELFMAG3)
40 return false;
41
42 if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
43 return false;
44 }
45
46 if (ehdr->e_machine != EM_AMD64) {
47 return false;
48 }
49
50 return true;
51}
unsigned char e_ident[EI_NIDENT]
Definition: elf64.h:65
Elf64_Half e_machine
Definition: elf64.h:67
#define EI_MAG2
Definition: elf_common.h:67
#define ELFMAG0
Definition: elf_common.h:79
#define ELFMAG3
Definition: elf_common.h:82
#define EI_MAG1
Definition: elf_common.h:66
#define EI_CLASS
Definition: elf_common.h:69
#define ELFMAG1
Definition: elf_common.h:80
#define EM_AMD64
Definition: elf_common.h:184
#define ELFMAG2
Definition: elf_common.h:81
#define ELFCLASS64
Definition: elf_common.h:93
#define EI_MAG0
Definition: elf_common.h:65
#define EI_MAG3
Definition: elf_common.h:68
Here is the caller graph for this function:

◆ Loader_Load()

bool Loader_Load ( Thread thr,
VNode vn,
void *  buf,
uint64_t  len 
)

Loader_Load –

Load the ELF binary into the process belonging to the thread.

Definition at line 131 of file loader.c.

132{
133 int i;
134 const Elf64_Ehdr *ehdr;
135 const Elf64_Phdr *phdr;
136 AS *as = thr->space;
137
138 ehdr = (const Elf64_Ehdr *)(buf);
139 phdr = (const Elf64_Phdr *)(buf + ehdr->e_phoff);
140
141 if (!Loader_CheckHeader(ehdr)) {
142 Log(loader, "Not a valid executable!\n");
143 return false;
144 }
145
146 Log(loader, "%8s %16s %8s %8s\n", "Offset", "VAddr", "FileSize", "MemSize");
147 for (i = 0; i < ehdr->e_phnum; i++)
148 {
149 ASSERT(phdr[i].p_type != PT_DYNAMIC);
150 if (phdr[i].p_type == PT_LOAD) {
151 uint64_t va = phdr[i].p_vaddr;
152 uint64_t memsz = phdr[i].p_memsz;
153 Log(loader, "%08llx %016llx %08llx %08llx\n", phdr[i].p_offset,
154 phdr[i].p_vaddr, phdr[i].p_filesz, phdr[i].p_memsz);
155
156 // Make sure it is page aligned
157 va = va & ~(uint64_t)PGMASK;
158 memsz += phdr[i].p_vaddr - va;
159
160 Log(loader, "AllocMap %016llx %08llx\n", va, memsz);
161 if (!PMap_AllocMap(as, va, memsz, PTE_W)) {
162 // XXX: Cleanup!
163 ASSERT(false);
164 return false;
165 }
166 }
167 }
168
170
171 /* XXXFILLMEIN: Load the ELF segments. */
172
173 /* Save the process entry point (i.e., _start) */
174 thr->proc->entrypoint = ehdr->e_entry;
175
176 return true;
177}
#define PTE_W
Definition: amd64.h:36
#define PGMASK
Definition: amd64.h:22
Elf64_Xword p_memsz
Definition: elf64.h:110
Elf64_Addr p_vaddr
Definition: elf64.h:107
Elf64_Addr e_entry
Definition: elf64.h:69
Elf64_Off e_phoff
Definition: elf64.h:70
Elf64_Half e_phnum
Definition: elf64.h:75
#define PT_DYNAMIC
Definition: elf_common.h:319
#define PT_LOAD
Definition: elf_common.h:318
static char buf[4096]
Definition: ethdump.c:10
#define Log(_module, _format,...)
Definition: kassert.h:32
#define ASSERT(_x)
Definition: kassert.h:8
bool Loader_CheckHeader(const Elf64_Ehdr *ehdr)
Definition: loader.c:34
#define MEM_USERSPACE_STKLEN
Definition: pmap.h:37
#define MEM_USERSPACE_STKBASE
Definition: pmap.h:36
bool PMap_AllocMap(AS *as, uint64_t virt, uint64_t len, uint64_t flags)
Definition: pmap.c:423
Definition: pmap.h:52
uintptr_t entrypoint
Definition: thread.h:69
struct Process * proc
Definition: thread.h:39
AS * space
Definition: thread.h:33
unsigned long uint64_t
Definition: types.h:13
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Loader_LoadInit()

void Loader_LoadInit ( )

Loader_LoadInit –

The init process is created from the execution kernel thread that initializes the system. This function initializes the thread and process state then loads the init binary.

Definition at line 187 of file loader.c.

188{
189 int status;
190 void *pg;
191 VNode *initvn;
192
193 pg = PAlloc_AllocPage();
194 if (!pg)
195 Panic("Not enough memory!");
196
197 initvn = VFS_Lookup("/sbin/init");
198 status = VFS_Open(initvn);
199 if (status < 0)
200 Panic("Loading init process failed!");
201 status = VFS_Read(initvn, pg, 0, 1024);
202 if (status < 0)
203 Panic("Reading init process failed!");
204
205 Thread *thr = Sched_Current();
206
207 // Open stdin/out/err
208 Handle *handle = Console_OpenHandle();
209 Handle_Add(thr->proc, handle);
210 handle = Console_OpenHandle();
211 Handle_Add(thr->proc, handle);
212 handle = Console_OpenHandle();
213 Handle_Add(thr->proc, handle);
214
215 /*
216 * Load init binary
217 */
218 Loader_Load(thr, initvn, pg, 1024);
219
220 VFS_Close(initvn);
221
222 Log(loader, "Jumping to userspace\n");
223
224 /*
225 * Reload the page tables for the current process
226 */
227 PMap_LoadAS(thr->space); // Reload CR3
228
229 /*
230 * Pass in zero arguments with null pointers to init
231 */
232 uintptr_t ap[3];
233 ap[0] = 0;
234 ap[1] = 0;
235 ap[2] = 0xDEADBEEF;
237
238 Copy_Out(&ap[0], rsp, sizeof(uintptr_t)*3);
239
240 /*
241 * The last step is to return into userspace handing control to init. We
242 * create a valid trap frame and return into userspace using Trap_Pop().
243 */
244 TrapFrame tf;
245 memset(&tf, 0, sizeof(tf));
246 tf.ds = SEL_UDS | 3;
247 tf.rip = thr->proc->entrypoint;
248 tf.cs = SEL_UCS | 3;
249 tf.rsp = rsp;
250 tf.ss = SEL_UDS | 3;
251 tf.rflags = RFLAGS_IF;
252 tf.rdi = rsp;
253 Trap_Pop(&tf);
254
255 /*
256 * We should never reach this point!
257 */
258 Panic("Unreachable: Trap_Pop() returned!\n");
259}
#define RFLAGS_IF
Definition: amd64.h:180
#define SEL_UDS
Definition: amd64.h:84
#define SEL_UCS
Definition: amd64.h:83
int Copy_Out(void *fromkernel, uintptr_t touser, uintptr_t len)
Definition: copy.c:70
uint64_t Handle_Add(Process *proc, Handle *handle)
Definition: handle.c:47
Thread * Sched_Current()
Definition: sched.c:56
void * PAlloc_AllocPage()
Definition: palloc.c:188
#define PGSIZE
Definition: malloc.c:21
bool Loader_Load(Thread *thr, VNode *vn, void *buf, uint64_t len)
Definition: loader.c:131
Handle * Console_OpenHandle()
Definition: console.c:200
#define MEM_USERSPACE_STKTOP
Definition: pmap.h:38
void PMap_LoadAS(AS *space)
Definition: pmap.c:182
void * memset(void *dst, int c, size_t len)
Definition: string.c:164
Definition: thread.h:31
uint16_t cs
Definition: trap.h:73
uint16_t ss
Definition: trap.h:79
uint64_t rsp
Definition: trap.h:78
uint64_t rip
Definition: trap.h:72
uint64_t rdi
Definition: trap.h:61
void Trap_Pop(TrapFrame *tf)
uint64_t rflags
Definition: trap.h:77
uint64_t ds
Definition: trap.h:66
Definition: trap.h:51
uint64_t uintptr_t
Definition: types.h:16
int VFS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len)
Definition: vfs.c:180
VNode * VFS_Lookup(const char *path)
Definition: vfs.c:63
int VFS_Open(VNode *fn)
Definition: vfs.c:147
int VFS_Close(VNode *fn)
Definition: vfs.c:162
Definition: vfs.h:24
void Panic(const char *str)
Definition: vgacons.c:164
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LoaderLoadSegment()

static void LoaderLoadSegment ( AS as,
VNode vn,
uintptr_t  vaddr,
uintptr_t  offset,
uintptr_t  len 
)
static

LoaderLoadSegment –

Loads a single segment into the target address space. This function loads a single page at a time because it has to lookup the address mappings through the page tables.

Definition at line 61 of file loader.c.

63{
64 void *raddr;
65
66 if ((vaddr % PGSIZE) != 0) {
67 uintptr_t maxlen = PGSIZE - (vaddr % PGSIZE);
68 uintptr_t rlen = maxlen < len ? maxlen : len;
69
70 raddr = (void *)DMPA2VA(PMap_Translate(as, vaddr));
71 VFS_Read(vn, raddr, offset, rlen);
72 vaddr += rlen;
73 offset += rlen;
74 len -= rlen;
75 }
76
77 while (len > PGSIZE) {
78 raddr = (void *)DMPA2VA(PMap_Translate(as, vaddr));
79 VFS_Read(vn, raddr, offset, PGSIZE);
80 vaddr += PGSIZE;
81 offset += PGSIZE;
82 len -= PGSIZE;
83 }
84
85 if (len > 0) {
86 raddr = (void *)DMPA2VA(PMap_Translate(as, vaddr));
87 VFS_Read(vn, raddr, offset, len);
88 }
89}
uint64_t len
Definition: multiboot.h:2
uintptr_t PMap_Translate(AS *space, uintptr_t va)
Definition: pmap.c:220
#define DMPA2VA(pa)
Definition: pmap.h:48
Here is the call graph for this function:

◆ LoaderZeroSegment()

static void LoaderZeroSegment ( AS as,
uintptr_t  vaddr,
uintptr_t  len 
)
static

LoaderZeroSegment –

Zeroes a segment of memory in the target address space. This is done one page a time while translating the virtual address to physical.

Definition at line 98 of file loader.c.

99{
100 void *raddr;
101
102 if ((vaddr % PGSIZE) != 0) {
103 uintptr_t maxlen = PGSIZE - (vaddr % PGSIZE);
104 uintptr_t rlen = maxlen < len ? maxlen : len;
105
106 raddr = (void *)DMPA2VA(PMap_Translate(as, vaddr));
107 memset(raddr, 0, rlen);
108 vaddr += rlen;
109 len -= rlen;
110 }
111
112 while (len > PGSIZE) {
113 raddr = (void *)DMPA2VA(PMap_Translate(as, vaddr));
114 memset(raddr, 0, PGSIZE);
115 vaddr += PGSIZE;
116 len -= PGSIZE;
117 }
118
119 if (len > 0) {
120 raddr = (void *)DMPA2VA(PMap_Translate(as, vaddr));
121 memset(raddr, 0, len);
122 }
123}
Here is the call graph for this function: