SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 /* Copyright (C) 2005 David Decotigny
002 
003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any later version.
007    
008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details.
012    
013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA. 
017 */
018 
019 #include <sos/kmalloc.h>
020 #include <sos/assert.h>
021 #include <sos/physmem.h>
022 #include <drivers/bochs.h>
023 #include <hwcore/paging.h>
024 #include <drivers/zero.h>
025 
026 #include "binfmt_elf32.h"
027 
028 
029 /**
030  * The "C" structure of a user program image in the kernel. Structures
031  * like this are created by the Makefile in the userland/ directory
032  */
033 struct userprog_entry
034 {
035   const char *name;
036   sos_vaddr_t bottom_vaddr;
037   sos_vaddr_t top_vaddr;
038 };
039 
040 
041 /**
042  * Symbol marking the start of the userprogs table, as setup by the
043  * ld script in the userland/ directory
044  */
045 extern char _userprogs_table;
046 
047 
048 /**
049  * Structure of a mapped resource for an ELF32 program (ie a portion
050  * of the kernel space)
051  */
052 struct elf32_mapped_program
053 {
054   sos_vaddr_t vaddr;
055   sos_size_t  size;
056   int ref_cnt;
057 
058   struct sos_umem_vmm_mapped_resource mr;
059 };
060 
061 
062 /** Called after the virtual region has been inserted inside its
063     address space */
064 static void elf32prog_ref(struct sos_umem_vmm_vr * vr)
065 {
066   struct elf32_mapped_program * elf32prog_resource;
067   elf32prog_resource = (struct elf32_mapped_program*) sos_umem_vmm_get_mapped_resource_of_vr(vr)->custom_data;
068   
069   elf32prog_resource->ref_cnt ++;
070 }
071 
072 
073 /** Called when the virtual region is removed from its address
074     space */
075 static void elf32prog_unref(struct sos_umem_vmm_vr * vr)
076 {
077   struct elf32_mapped_program * elf32prog_resource;
078   elf32prog_resource
079     = (struct elf32_mapped_program*)
080       sos_umem_vmm_get_mapped_resource_of_vr(vr)->custom_data;
081   
082   elf32prog_resource->ref_cnt --;
083   SOS_ASSERT_FATAL(elf32prog_resource->ref_cnt >= 0);
084 
085   /* Free the resource if it becomes unused */
086   if (elf32prog_resource->ref_cnt == 0)
087     sos_kfree((sos_vaddr_t)elf32prog_resource);
088 }
089 
090 
091 /** Called when a legitimate page fault is occuring in the VR */
092 static sos_ret_t elf32prog_page_in(struct sos_umem_vmm_vr * vr,
093                                    sos_uaddr_t uaddr,
094                                    sos_bool_t write_access)
095 {
096   struct elf32_mapped_program * elf32prog_resource;
097   sos_ret_t     retval = SOS_OK;
098   sos_paddr_t   ppage_paddr;
099   sos_uaddr_t   upage_uaddr = SOS_PAGE_ALIGN_INF(uaddr);
100   sos_uoffset_t offset_in_prog;
101   sos_size_t    size_to_copy;
102   sos_ui32_t    access_rights = sos_umem_vmm_get_prot_of_vr(vr);
103 
104   elf32prog_resource
105     = (struct elf32_mapped_program*)
106       sos_umem_vmm_get_mapped_resource_of_vr(vr)->custom_data;
107 
108   /* Compute the offset in program of the page, and the size to copy
109      in user space */
110   offset_in_prog = upage_uaddr - sos_umem_vmm_get_start_of_vr(vr)
111     + sos_umem_vmm_get_offset_in_resource(vr);
112   size_to_copy = SOS_PAGE_SIZE;
113   if (offset_in_prog + size_to_copy > elf32prog_resource->size)
114     size_to_copy = elf32prog_resource->size - offset_in_prog;
115 
116   /* If the source page is also aligned, simply remap the kernel area
117      into user space */
118   if (SOS_IS_PAGE_ALIGNED(elf32prog_resource->vaddr + offset_in_prog))
119     {
120       sos_vaddr_t kern_vaddr = elf32prog_resource->vaddr + offset_in_prog;
121 
122       ppage_paddr = sos_paging_get_paddr(kern_vaddr);
123 
124       /* Remap it in user space, in read-only mode (to force COW) */
125       retval = sos_paging_map(ppage_paddr,
126                               upage_uaddr,
127                               TRUE,
128                               access_rights & ~SOS_VM_MAP_PROT_WRITE);
129       SOS_ASSERT_FATAL(SOS_OK == retval);
130     }
131 
132   /* Otherwise we need to allocate a new page */
133   else
134     {
135       /* Allocate a new page that contains the code/data of the
136          program */
137       ppage_paddr = sos_physmem_ref_physpage_new(FALSE);
138       if (! ppage_paddr)
139         return -SOS_ENOMEM;
140       
141       /* Map it in user space, in read/write mode for the kernel to copy
142          the data in the page */
143       retval = sos_paging_map(ppage_paddr,
144                               upage_uaddr,
145                               TRUE,
146                               access_rights | SOS_VM_MAP_PROT_WRITE);
147       SOS_ASSERT_FATAL(SOS_OK == retval);
148       sos_physmem_unref_physpage(ppage_paddr);
149       
150       /* Copy the program in it */
151       memcpy((void*)upage_uaddr,
152              (void*)elf32prog_resource->vaddr + offset_in_prog,
153              size_to_copy);
154       if (size_to_copy < SOS_PAGE_SIZE)
155         memset((void*)(upage_uaddr + size_to_copy), 0x0,
156                SOS_PAGE_SIZE - size_to_copy);
157       
158       /* Change it read-only if needed */
159       if (! (access_rights & SOS_VM_MAP_PROT_WRITE))
160         return sos_paging_set_prot(upage_uaddr,
161                                    access_rights & ~SOS_VM_MAP_PROT_WRITE);
162     }
163    
164   return retval;
165 }
166 
167 
168 static struct sos_umem_vmm_vr_ops elf32prog_ops = (struct sos_umem_vmm_vr_ops)
169 {
170   .ref     = elf32prog_ref,
171   .unref   = elf32prog_unref,
172   .page_in = elf32prog_page_in,
173   .unmap   = NULL /* ignored */
174 };
175 
176 
177 static sos_ret_t elf32prog_mmap(struct sos_umem_vmm_vr *vr)
178 {
179   return sos_umem_vmm_set_ops_of_vr(vr, &elf32prog_ops);
180 }
181 
182 
183 /*
184  * Local functions
185  */
186 
187 
188 /**
189  * Function to locate the given user program image in the kernel memory
190  */
191 static struct userprog_entry * lookup_userprog(const char *name);
192 
193 
194 sos_uaddr_t sos_binfmt_elf32_map(struct sos_umem_vmm_as * dest_as,
195                                  const char * progname)
196 {
197   int i;
198 
199   /**
200    * Typedefs, constants and structure definitions as given by the ELF
201    * standard specifications.
202    */
203   typedef unsigned long  Elf32_Addr;
204   typedef unsigned long  Elf32_Word;
205   typedef unsigned short Elf32_Half;
206   typedef unsigned long  Elf32_Off;
207   typedef signed long    Elf32_Sword;
208   
209   /* Elf identification */
210   
211 #define EI_NIDENT 16
212   typedef struct {
213     unsigned char       e_ident[EI_NIDENT];
214     Elf32_Half          e_type;
215     Elf32_Half          e_machine;
216     Elf32_Word          e_version;
217     Elf32_Addr          e_entry;
218     Elf32_Off           e_phoff;
219     Elf32_Off           e_shoff;
220     Elf32_Word          e_flags;
221     Elf32_Half          e_ehsize;
222     Elf32_Half          e_phentsize;
223     Elf32_Half          e_phnum;
224     Elf32_Half          e_shentsize;
225     Elf32_Half          e_shnum;
226     Elf32_Half          e_shstrndx;
227   } __attribute__((packed)) Elf32_Ehdr_t;
228   
229 /* e_ident value */
230 #define ELFMAG0 0x7f
231 #define ELFMAG1 'E'
232 #define ELFMAG2 'L'
233 #define ELFMAG3 'F'
234 
235 /* e_ident offsets */
236 #define EI_MAG0         0
237 #define EI_MAG1         1
238 #define EI_MAG2         2
239 #define EI_MAG3         3
240 #define EI_CLASS        4
241 #define EI_DATA         5
242 #define EI_VERSION      6
243 #define EI_PAD          7
244 
245 /* e_ident[EI_CLASS] */
246 #define ELFCLASSNONE    0
247 #define ELFCLASS32      1
248 #define ELFCLASS64      2
249 
250 /* e_ident[EI_DATA] */
251 #define ELFDATANONE     0
252 #define ELFDATA2LSB     1
253 #define ELFDATA2MSB     2
254 
255 /* e_type */
256 #define ET_NONE         0  /* No file type       */
257 #define ET_REL          1  /* Relocatable file   */
258 #define ET_EXEC         2  /* Executable file    */
259 #define ET_DYN          3  /* Shared object file */
260 #define ET_CORE         4  /* Core file          */
261 #define ET_LOPROC  0xff00  /* Processor-specific */
262 #define ET_HIPROC  0xffff  /* Processor-specific */
263 
264 /* e_machine */
265 #define EM_NONE       0  /* No machine     */
266 #define EM_M32        1  /* AT&T WE 32100  */
267 #define EM_SPARC      2  /* SPARC          */
268 #define EM_386        3  /* Intel 80386    */
269 #define EM_68K        4  /* Motorola 68000 */
270 #define EM_88K        5  /* Motorola 88000 */
271 #define EM_860        7  /* Intel 80860    */
272 #define EM_MIPS       8  /* MIPS RS3000    */
273 
274 /* e_version */
275 #define EV_NONE    0 /* invalid version */
276 #define EV_CURRENT 1 /* current version */
277 
278   typedef struct {
279     Elf32_Word    p_type;
280     Elf32_Off     p_offset;
281     Elf32_Addr    p_vaddr;
282     Elf32_Addr    p_paddr;
283     Elf32_Word    p_filesz;
284     Elf32_Word    p_memsz;
285     Elf32_Word    p_flags;
286     Elf32_Word    p_align;
287   } __attribute__((packed)) Elf32_Phdr_t;
288 
289 /* Reserved segment types p_type */
290 #define PT_NULL    0
291 #define PT_LOAD    1
292 #define PT_DYNAMIC 2
293 #define PT_INTERP  3
294 #define PT_NOTE    4
295 #define PT_SHLIB   5
296 #define PT_PHDR    6
297 #define PT_LOPROC  0x70000000
298 #define PT_HIPROC  0x7fffffff
299 
300 /* p_flags */
301 #define PF_X       1
302 #define PF_W       2
303 #define PF_R       4
304 
305 
306   Elf32_Ehdr_t *elf_hdr;
307   Elf32_Phdr_t *elf_phdrs;
308 
309   struct elf32_mapped_program * mapped_prog;
310   struct userprog_entry * prog;
311   sos_uaddr_t prog_top_user_address = 0;
312 
313   mapped_prog
314     = (struct elf32_mapped_program*)
315       sos_kmalloc(sizeof(struct elf32_mapped_program), 0);
316   if (! mapped_prog)
317     return -SOS_ENOMEM;
318 
319   prog = lookup_userprog(progname);
320   if (! prog)
321     {
322       sos_kfree((sos_vaddr_t)mapped_prog);
323       return 0;
324     }
325 
326   /* Initialize mapped resource */
327   memset(mapped_prog, 0x0, sizeof(*mapped_prog));
328   mapped_prog->mr.custom_data = mapped_prog;
329   mapped_prog->mr.mmap        = elf32prog_mmap;
330   mapped_prog->mr.allowed_access_rights
331     = SOS_VM_MAP_PROT_READ
332     | SOS_VM_MAP_PROT_WRITE
333     | SOS_VM_MAP_PROT_EXEC;
334   mapped_prog->vaddr          = prog->bottom_vaddr;
335   mapped_prog->size           = prog->top_vaddr - prog->bottom_vaddr;
336   
337   elf_hdr = (Elf32_Ehdr_t*) prog->bottom_vaddr;
338 
339   /* Make sure the image is large enough to contain at least the ELF
340      header */
341   if (prog->bottom_vaddr + sizeof(Elf32_Ehdr_t) > prog->top_vaddr)
342     {
343       sos_bochs_printf("ELF prog %s: incorrect header\n", prog->name);
344       return 0;
345     }
346 
347   /* Macro to check expected values for some fields in the ELF header */
348 #define ELF_CHECK(hdr,field,expected_value) \
349   ({ if ((hdr)->field != (expected_value)) \
350      { \
351        sos_bochs_printf("ELF prog %s: for %s, expected %x, got %x\n", \
352                         prog->name, \
353                         #field, \
354                         (unsigned)(expected_value), \
355                         (unsigned)(hdr)->field); \
356        return 0; \
357      } \
358   })
359 
360   ELF_CHECK(elf_hdr, e_ident[EI_MAG0], ELFMAG0);
361   ELF_CHECK(elf_hdr, e_ident[EI_MAG1], ELFMAG1);
362   ELF_CHECK(elf_hdr, e_ident[EI_MAG2], ELFMAG2);
363   ELF_CHECK(elf_hdr, e_ident[EI_MAG3], ELFMAG3);
364   ELF_CHECK(elf_hdr, e_ident[EI_CLASS], ELFCLASS32);
365   ELF_CHECK(elf_hdr, e_ident[EI_DATA], ELFDATA2LSB);
366   ELF_CHECK(elf_hdr, e_type, ET_EXEC);
367   ELF_CHECK(elf_hdr, e_version, EV_CURRENT);
368 
369   /* Get the begining of the program header table */
370   elf_phdrs = (Elf32_Phdr_t*) (prog->bottom_vaddr + elf_hdr->e_phoff);
371 
372   /* Map the program segment in R/W mode. To make things clean, we
373      should iterate over the sections, not the program header */
374   for (i = 0 ; i < elf_hdr->e_phnum ; i++)
375     {
376       sos_ui32_t prot_flags;
377       sos_uaddr_t uaddr;
378 
379       /* Ignore the empty program headers that are not marked "LOAD" */
380       if (elf_phdrs[i].p_type != PT_LOAD)
381         {
382           if (elf_phdrs[i].p_memsz != 0)
383             {
384               sos_display_fatal_error("ELF: non-empty non-LOAD segments not supported yet");
385             }
386           continue;
387         }
388       
389       if (elf_phdrs[i].p_vaddr < SOS_PAGING_BASE_USER_ADDRESS)
390         {
391           sos_display_fatal_error("User program has an incorrect address");
392         }
393 
394       prot_flags = 0;
395       if (elf_phdrs[i].p_flags & SOS_VM_MAP_PROT_READ)
396         prot_flags |= SOS_VM_MAP_PROT_READ;
397       if (elf_phdrs[i].p_flags & SOS_VM_MAP_PROT_WRITE)
398         prot_flags |= SOS_VM_MAP_PROT_WRITE;
399       if (elf_phdrs[i].p_flags & SOS_VM_MAP_PROT_EXEC)
400         prot_flags |= SOS_VM_MAP_PROT_EXEC;
401 
402       uaddr = elf_phdrs[i].p_vaddr;
403       SOS_ASSERT_FATAL(SOS_IS_PAGE_ALIGNED(uaddr));
404 
405       /* First of all: map the region of the phdr which is also
406          covered by the file */
407       SOS_ASSERT_FATAL(SOS_OK
408                        == sos_umem_vmm_map(dest_as, &uaddr,
409                                            SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_filesz),
410                                            prot_flags,
411                                            /* PRIVATE */ SOS_VR_MAP_FIXED,
412                                            & mapped_prog->mr,
413                                            elf_phdrs[i].p_offset));
414 
415       /* Then map the remaining by a zero resource */
416       uaddr += SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_filesz);
417       if (SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_filesz)
418           < SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_memsz))
419         SOS_ASSERT_FATAL(SOS_OK
420                          == sos_dev_zero_map(dest_as, &uaddr,
421                                              SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_memsz)
422                                              - SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_filesz),
423                                              prot_flags,
424                                              /* PRIVATE */ SOS_VR_MAP_FIXED));
425 
426       if (prog_top_user_address
427           < uaddr + SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_memsz))
428         prog_top_user_address
429           = uaddr + SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_memsz);
430     }
431 
432   /* Now prepare the heap */
433   sos_umem_vmm_init_heap(dest_as, prog_top_user_address);
434 
435   return elf_hdr->e_entry;
436 }
437 
438 
439 /**
440  * Lookup a user program located inside the kernel's image
441  */
442 static struct userprog_entry * lookup_userprog(const char *name)
443 {
444   struct userprog_entry *prog;
445 
446   if (! name)
447     return NULL;
448 
449   /* Walk through the table of user program description structures to
450      find the user program with the given name */
451   for (prog = (struct userprog_entry*) & _userprogs_table ;
452        prog && (prog->name != NULL) ;
453        prog++)
454     {
455       if (0 == strcmp(name, prog->name))
456         /* Found it ! */
457         return prog;
458     }
459 
460   return NULL;
461 }

source navigation ] diff markup ] identifier search ] general search ]