]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ux/loader.cpp
update
[l4.git] / kernel / fiasco / src / kern / ux / loader.cpp
1
2 INTERFACE:
3
4 #include <cstdio>                       // for FILE *
5 #include "types.h"
6
7 class Multiboot_module;
8
9 class Loader
10 {
11 private:
12   static unsigned int phys_base;
13   static char const *errors[];
14
15 public:
16   static FILE *open_module (const char * const path);
17
18   static char const * load_module (const char * const path,
19                                    Multiboot_module *module,
20                                    unsigned long int memsize,
21                                    bool quiet,
22                                    unsigned long *start,
23                                    unsigned long *end);
24
25   static char const * copy_module (const char * const path,
26                                    Multiboot_module *module,
27                                    Address *load_addr,
28                                    bool quiet);
29 };
30
31 IMPLEMENTATION:
32
33 #include <cstdlib>
34 #include <cstring>
35 #include <elf.h>
36 #include <unistd.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include "config.h"
40 #include "initcalls.h"
41 #include "mem_layout.h"
42 #include "multiboot.h"
43
44 unsigned int Loader::phys_base = Mem_layout::Physmem;
45
46 char const *Loader::errors[] FIASCO_INITDATA =
47 {
48   "Failed to open file",
49   "Failed to load ELF header",
50   "Failed ELF magic check",
51   "Failed ELF version check",
52   "Failed to load program header",
53   "Failed to fit program section into memory",
54   "Failed to load program section from file",
55   "Failed to read module, out of memory?"
56 };
57
58 IMPLEMENT FIASCO_INIT
59 FILE *
60 Loader::open_module (const char * const path)
61 {
62   char magic[3];                // 2 + 1 for the terminating \0
63   FILE *fp;
64
65   if ((fp = fopen (path, "r")) == NULL)
66     return NULL;
67
68   fgets (magic, sizeof (magic), fp);
69
70   if (magic[0] == '\037' && magic[1] == '\213')         // GZIP
71     {
72       FILE *pp;
73       char pipecmd[256];
74       int c;
75
76       fclose (fp);
77
78       snprintf (pipecmd, sizeof (pipecmd), "zcat %s", path);
79
80       if ((pp = popen (pipecmd, "r")) == NULL)
81         return NULL;
82
83       if ((fp = tmpfile()) == NULL)
84         {
85           pclose (pp);
86           return NULL;
87         }
88
89       while ((c = fgetc (pp)) != EOF)
90         fputc (c, fp);
91
92       pclose (pp);
93     }
94
95   rewind (fp);
96
97   return fp;
98 }
99
100 IMPLEMENT FIASCO_INIT
101 char const *
102 Loader::load_module (const char * const path,
103                      Multiboot_module *module,
104                      unsigned long int memsize,
105                      bool quiet,
106                      unsigned long *start,
107                      unsigned long *end)
108 {
109   FILE *fp;
110   Elf32_Ehdr eh;
111   Elf32_Phdr ph;
112   long offset;
113   int i;
114
115   if ((fp = open_module (path)) == NULL)
116     return errors[0];
117
118   // Load ELF Header
119   if (fread (&eh, sizeof (eh), 1, fp) != 1)
120     {
121       fclose (fp);
122       return errors[1];
123     }
124
125   // Check if valid ELF magic, 32bit, little endian
126   if (memcmp(eh.e_ident, ELFMAG, 4) != 0 ||
127       eh.e_ident[EI_CLASS] != ELFCLASS32  ||
128       eh.e_ident[EI_DATA]  != ELFDATA2LSB)
129     {
130       fclose (fp);
131       return errors[2];
132     }
133
134   // Check if executable, i386 format, current ELF version
135   if (eh.e_type    != ET_EXEC ||
136       eh.e_machine != EM_386  ||
137       eh.e_version != EV_CURRENT)
138     {
139       fclose (fp);
140       return errors[3];
141     }
142
143   // Record entry point (initial EIP)
144   module->reserved  = eh.e_entry;
145   *start            = 0xffffffff;
146   *end              = 0;
147
148   // Load all program sections
149   for (i = 0, offset = eh.e_phoff; i < eh.e_phnum; i++) {
150
151     // Load Program Header
152     if (fseek (fp, offset, SEEK_SET) == -1 ||
153         fread (&ph, sizeof (ph), 1, fp) != 1)
154       {
155         fclose (fp);
156         return errors[4];
157       }
158
159     offset += sizeof (ph);
160
161     // Only consider non-empty load-sections
162     if (ph.p_type != PT_LOAD || !ph.p_memsz)
163       continue;
164
165     // Check if section fits into memory
166     if (ph.p_paddr + ph.p_memsz > memsize)
167       {
168         fclose (fp);
169         return errors[5];
170       }
171
172     // Load Section with non-zero filesize
173     if (ph.p_filesz && (fseek (fp, ph.p_offset, SEEK_SET) == -1 ||
174         fread ((void *)(phys_base + ph.p_paddr), ph.p_filesz, 1, fp) != 1))
175       {
176         fclose (fp);
177         return errors[6];
178       }
179
180     // Zero-pad uninitialized data if filesize < memsize
181     if (ph.p_filesz < ph.p_memsz)
182       memset ((void *)(phys_base + ph.p_paddr + ph.p_filesz), 0,
183                ph.p_memsz - ph.p_filesz);
184
185     if (ph.p_paddr < *start)
186       *start = ph.p_paddr;
187     if (ph.p_paddr + ph.p_memsz > *end)
188       *end   = ph.p_paddr + ph.p_memsz;
189   }
190
191   if (! quiet)
192     printf ("Loading Module 0x"L4_PTR_FMT"-0x"L4_PTR_FMT" [%s]\n",
193             (Address)*start, (Address)*end, path);
194
195   fclose (fp);
196   return 0;
197 }
198
199 IMPLEMENT FIASCO_INIT
200 char const *
201 Loader::copy_module (const char * const path,
202                      Multiboot_module *module,
203                      Address *load_addr,
204                      bool quiet)
205 {
206   FILE *fp;
207   struct stat s;
208
209   if ((fp = open_module (path)) == NULL)
210     return errors[0];
211
212   if (fstat (fileno (fp), &s) == -1)
213     {
214       fclose (fp);
215       return errors[0];
216     }
217
218   *load_addr -= s.st_size;
219   *load_addr &= Config::PAGE_MASK;      // this may not be necessary
220
221   if (fread ((void *)(phys_base + *load_addr), s.st_size, 1, fp) != 1)
222     {
223       fclose (fp);
224       return errors[7];
225     }
226
227   module->mod_start = *load_addr;
228   module->mod_end   = *load_addr + s.st_size;
229
230   if (! quiet)
231     printf ("Copying Module 0x"L4_PTR_FMT"-0x"L4_PTR_FMT" [%s]\n",
232             (Address)module->mod_start, (Address)module->mod_end, path);
233
234   fclose (fp);
235   return 0;
236 }