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    Copyright (C) 1995  TIS Committee (ELF typedefs, constants and macros)
003 
004    This program is free software; you can redistribute it and/or
005    modify it under the terms of the GNU General Public License
006    as published by the Free Software Foundation; either version 2
007    of the License, or (at your option) any later version.
008    
009    This program is distributed in the hope that it will be useful,
010    but WITHOUT ANY WARRANTY; without even the implied warranty of
011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012    GNU General Public License for more details.
013    
014    You should have received a copy of the GNU General Public License
015    along with this program; if not, write to the Free Software
016    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
017    USA. 
018 */
019 
020 #include <sos/types.h>
021 #include <sos/klibc.h>
022 #include <drivers/bochs.h>
023 #include <sos/physmem.h>
024 #include <sos/assert.h>
025 
026 #include <sos/process.h>
027 #include <sos/thread.h>
028 
029 
030 /**
031  * @file test-art7.c
032  *
033  * Basic tests for the user thread/process management API
034  */
035 
036 
037 /**
038  * The "C" structure of a user program image in the kernel. Structures
039  * like this are created by the Makefile in the userland/ directory
040  */
041 struct userprog_entry
042 {
043   const char *name;
044   sos_vaddr_t bottom_vaddr;
045   sos_vaddr_t top_vaddr;
046 };
047 
048 
049 /**
050  * Symbol marking the start of the userprogs table, as setup by the
051  * ld script in the userland/ directory
052  */
053 extern char _userprogs_table;
054 
055 
056 /*
057  * Local functions
058  */
059 
060 
061 /**
062  * Function to locate the given user program image in the kernel memory
063  */
064 static struct userprog_entry * lookup_userprog(const char *name);
065 
066 
067 /**
068  * Function to create a new process containing the given USER program
069  * image. This function automatically locates the destination addresses
070  * of the program by examinating its ELF header
071  *
072  * @return The address of the first instruction of the program, as
073  * given by its ELF header, or 0 when the program is not a correct ELF
074  * image.
075  */
076 static sos_uaddr_t load_elf_prog(const struct userprog_entry *prog);
077 
078 
079 /**
080  * Function that locates a USER program in the kernel image, creates a
081  * new USER process for it, and creates the given nb_uthreads USER
082  * threads inside it.
083  */
084 static sos_ret_t spawn_program(const char *progname,
085                                unsigned nb_uthreads);
086 
087 
088 /**
089  * The main function for our tests
090  */
091 void test_art7()
092 {
093   spawn_program("myprog5", 5);
094   spawn_program("myprog1", 10);
095   spawn_program("myprog5", 1);
096   spawn_program("myprog6", 12);
097   spawn_program("myprog2", 10);
098   spawn_program("myprog5", 1);
099   spawn_program("myprog3", 10);
100   spawn_program("myprog5", 1);
101   spawn_program("myprog1", 10);
102   spawn_program("myprog6", 12);
103   spawn_program("myprog5", 1);
104   spawn_program("myprog4", 10);
105   spawn_program("myprog5", 1);
106   spawn_program("myprog2", 10);
107   spawn_program("myprog6", 12);
108   spawn_program("myprog5", 1);
109 }
110 
111 
112 static sos_ret_t spawn_program(const char *progname,
113                                unsigned nb_uthreads)
114 {
115   int i;
116   
117   sos_uaddr_t prog_entry, stack_top_uaddr;
118   struct userprog_entry *prog;
119   struct sos_process *new_proc;
120 
121   prog = lookup_userprog(progname);
122   if (! prog)
123     return -SOS_EINVAL;
124 
125   new_proc = sos_process_create_empty(progname);
126   if (! new_proc)
127     return -SOS_ENOMEM;
128 
129   /* Squat this new process to map the user program into it */
130   SOS_ASSERT_FATAL(SOS_OK
131                    == sos_thread_change_current_mm_context(sos_process_get_mm_context(new_proc)));
132 
133   /* Load the user program image */
134   prog_entry = load_elf_prog(prog);
135   if (! prog_entry)
136     {
137       sos_process_unref(new_proc);
138       return -SOS_ENOMEM;
139     }
140 
141   /* Map the user stacks into it and create the user threads */
142   /* By default, the first user stack will be located at the end of
143      the user address space (ie 4GB), the stacks of the other threads
144      will be located (12 pages) below. Each stack is USTACK_NPAGES
145      pages long */  
146 #define USTACK_NPAGES 8
147   for (i = 0, stack_top_uaddr = 0xfffffffc ;
148        i < nb_uthreads ;
149        i++, stack_top_uaddr -= (USTACK_NPAGES + 4)*SOS_PAGE_SIZE)
150     {
151       int p;
152       char thrname[16];
153       sos_uaddr_t stack_base = SOS_PAGE_ALIGN_INF(stack_top_uaddr);
154 
155       /* Allocate USTACK_NPAGES pages for the stack and map them */
156       for (p = 0 ; p < USTACK_NPAGES ; p++, stack_base -= SOS_PAGE_SIZE)
157         {
158           sos_ret_t retval;
159           sos_paddr_t ppage;
160           
161           ppage = sos_physmem_ref_physpage_new(FALSE);
162           SOS_ASSERT_FATAL(ppage != 0);
163           
164           /* Map it in the process space. Might fail is there is not
165              enough RAM (we don't support swap-out for the moment) */
166           retval = sos_paging_map(ppage, stack_base, TRUE,
167                                   SOS_VM_MAP_PROT_READ
168                                   | SOS_VM_MAP_PROT_WRITE);
169           SOS_ASSERT_FATAL(retval == SOS_OK);
170           
171           retval = sos_physmem_unref_physpage(ppage);
172           SOS_ASSERT_FATAL(retval == 0);
173           
174           /* Poison the stack to detect the use of uninitialized
175              variables */
176           memset((void*)stack_base, 0xa5, SOS_PAGE_SIZE);
177         }
178       
179       /* Create the user thread */
180       snprintf(thrname, sizeof(thrname), "%s:%d", progname, i);
181       sos_bochs_printf("Spawning %s\n", thrname);
182       sos_create_user_thread(thrname,
183                              new_proc,
184                              prog_entry,
185                              0, 0,
186                              stack_top_uaddr,
187                              SOS_SCHED_PRIO_TS_LOWEST);
188 
189       sos_thread_yield();
190     }
191 
192   /* Don't need the reference to the process anymore */
193   sos_process_unref(new_proc);
194 
195   /* Revert to normal kernel thread's address space */
196   SOS_ASSERT_FATAL(SOS_OK
197                    == sos_thread_change_current_mm_context(NULL));
198 
199   return SOS_OK;
200 }
201 
202 
203 /**
204  * Lookup a user program located inside the kernel's image
205  */
206 static struct userprog_entry * lookup_userprog(const char *name)
207 {
208   struct userprog_entry *prog;
209 
210   if (! name)
211     return NULL;
212 
213   /* Walk through the table of user program description structures to
214      find the user program with the given name */
215   for (prog = (struct userprog_entry*) & _userprogs_table ;
216        prog && (prog->name != NULL) ;
217        prog++)
218     {
219       if (0 == strcmp(name, prog->name))
220         /* Found it ! */
221         return prog;
222     }
223 
224   return NULL;
225 }
226 
227 
228 /**
229  * Make sure the program is in a valid ELF format, map it into memory,
230  * and return the address of its entry point (ie _start function)
231  *
232  * @return 0 when the program is not a valid ELF
233  */
234 static sos_uaddr_t load_elf_prog(const struct userprog_entry *prog)
235 {
236   int i;
237 
238   /**
239    * Typedefs, constants and structure definitions as given by the ELF
240    * standard specifications.
241    */
242   typedef unsigned long  Elf32_Addr;
243   typedef unsigned long  Elf32_Word;
244   typedef unsigned short Elf32_Half;
245   typedef unsigned long  Elf32_Off;
246   typedef signed long    Elf32_Sword;
247   
248   /* Elf identification */
249   
250 #define EI_NIDENT 16
251   typedef struct {
252     unsigned char       e_ident[EI_NIDENT];
253     Elf32_Half          e_type;
254     Elf32_Half          e_machine;
255     Elf32_Word          e_version;
256     Elf32_Addr          e_entry;
257     Elf32_Off           e_phoff;
258     Elf32_Off           e_shoff;
259     Elf32_Word          e_flags;
260     Elf32_Half          e_ehsize;
261     Elf32_Half          e_phentsize;
262     Elf32_Half          e_phnum;
263     Elf32_Half          e_shentsize;
264     Elf32_Half          e_shnum;
265     Elf32_Half          e_shstrndx;
266   } __attribute__((packed)) Elf32_Ehdr_t;
267   
268 /* e_ident value */
269 #define ELFMAG0 0x7f
270 #define ELFMAG1 'E'
271 #define ELFMAG2 'L'
272 #define ELFMAG3 'F'
273 
274 /* e_ident offsets */
275 #define EI_MAG0         0
276 #define EI_MAG1         1
277 #define EI_MAG2         2
278 #define EI_MAG3         3
279 #define EI_CLASS        4
280 #define EI_DATA         5
281 #define EI_VERSION      6
282 #define EI_PAD          7
283 
284 /* e_ident[EI_CLASS] */
285 #define ELFCLASSNONE    0
286 #define ELFCLASS32      1
287 #define ELFCLASS64      2
288 
289 /* e_ident[EI_DATA] */
290 #define ELFDATANONE     0
291 #define ELFDATA2LSB     1
292 #define ELFDATA2MSB     2
293 
294 /* e_type */
295 #define ET_NONE         0  /* No file type       */
296 #define ET_REL          1  /* Relocatable file   */
297 #define ET_EXEC         2  /* Executable file    */
298 #define ET_DYN          3  /* Shared object file */
299 #define ET_CORE         4  /* Core file          */
300 #define ET_LOPROC  0xff00  /* Processor-specific */
301 #define ET_HIPROC  0xffff  /* Processor-specific */
302 
303 /* e_machine */
304 #define EM_NONE       0  /* No machine     */
305 #define EM_M32        1  /* AT&T WE 32100  */
306 #define EM_SPARC      2  /* SPARC          */
307 #define EM_386        3  /* Intel 80386    */
308 #define EM_68K        4  /* Motorola 68000 */
309 #define EM_88K        5  /* Motorola 88000 */
310 #define EM_860        7  /* Intel 80860    */
311 #define EM_MIPS       8  /* MIPS RS3000    */
312 
313 /* e_version */
314 #define EV_NONE    0 /* invalid version */
315 #define EV_CURRENT 1 /* current version */
316 
317   typedef struct {
318     Elf32_Word    p_type;
319     Elf32_Off     p_offset;
320     Elf32_Addr    p_vaddr;
321     Elf32_Addr    p_paddr;
322     Elf32_Word    p_filesz;
323     Elf32_Word    p_memsz;
324     Elf32_Word    p_flags;
325     Elf32_Word    p_align;
326   } __attribute__((packed)) Elf32_Phdr_t;
327 
328 /* Reserved segment types p_type */
329 #define PT_NULL    0
330 #define PT_LOAD    1
331 #define PT_DYNAMIC 2
332 #define PT_INTERP  3
333 #define PT_NOTE    4
334 #define PT_SHLIB   5
335 #define PT_PHDR    6
336 #define PT_LOPROC  0x70000000
337 #define PT_HIPROC  0x7fffffff
338 
339 /* p_flags */
340 #define PF_X       1
341 #define PF_W       2
342 #define PF_R       4
343 
344 
345   Elf32_Ehdr_t *elf_hdr = (Elf32_Ehdr_t*) prog->bottom_vaddr;
346   Elf32_Phdr_t *elf_phdrs;
347 
348   /* Make sure the image is large enough to contain at least the ELF
349      header */
350   if (prog->bottom_vaddr + sizeof(Elf32_Ehdr_t) > prog->top_vaddr)
351     {
352       sos_bochs_printf("ELF prog %s: incorrect header\n", prog->name);
353       return 0;
354     }
355 
356   /* Macro to check expected values for some fields in the ELF header */
357 #define ELF_CHECK(hdr,field,expected_value) \
358   ({ if ((hdr)->field != (expected_value)) \
359      { \
360        sos_bochs_printf("ELF prog %s: for %s, expected %x, got %x\n", \
361                         prog->name, \
362                         #field, \
363                         (unsigned)(expected_value), \
364                         (unsigned)(hdr)->field); \
365        return 0; \
366      } \
367   })
368 
369   ELF_CHECK(elf_hdr, e_ident[EI_MAG0], ELFMAG0);
370   ELF_CHECK(elf_hdr, e_ident[EI_MAG1], ELFMAG1);
371   ELF_CHECK(elf_hdr, e_ident[EI_MAG2], ELFMAG2);
372   ELF_CHECK(elf_hdr, e_ident[EI_MAG3], ELFMAG3);
373   ELF_CHECK(elf_hdr, e_ident[EI_CLASS], ELFCLASS32);
374   ELF_CHECK(elf_hdr, e_ident[EI_DATA], ELFDATA2LSB);
375   ELF_CHECK(elf_hdr, e_type, ET_EXEC);
376   ELF_CHECK(elf_hdr, e_version, EV_CURRENT);
377 
378   /* Get the begining of the program header table */
379   elf_phdrs = (Elf32_Phdr_t*) (prog->bottom_vaddr + elf_hdr->e_phoff);
380 
381   /* Map the program segment in R/W mode. To make things clean, we
382      should iterate over the sections, not the program header */
383   for (i = 0 ; i < elf_hdr->e_phnum ; i++)
384     {
385       sos_uaddr_t uaddr;
386 
387       /* Ignore the empty program headers that are not marked "LOAD" */
388       if (elf_phdrs[i].p_type != PT_LOAD)
389         {
390           if (elf_phdrs[i].p_memsz != 0)
391             {
392               SOS_FATAL_ERROR("ELF: non-empty non-LOAD segments not supported yet");
393             }
394           continue;
395         }
396       
397       if (elf_phdrs[i].p_vaddr < SOS_PAGING_BASE_USER_ADDRESS)
398         {
399           SOS_FATAL_ERROR("User program has an incorrect address");
400         }
401 
402       /* Map pages of physical memory into user space */
403       for (uaddr = SOS_PAGE_ALIGN_INF(elf_phdrs[i].p_vaddr) ;
404            uaddr < elf_phdrs[i].p_vaddr + elf_phdrs[i].p_memsz ;
405            uaddr += SOS_PAGE_SIZE)
406         {
407           sos_ret_t retval;
408           sos_paddr_t ppage;
409           ppage = sos_physmem_ref_physpage_new(TRUE);
410 
411           retval = sos_paging_map(ppage, uaddr, TRUE,
412                                   SOS_VM_MAP_PROT_READ
413                                   | SOS_VM_MAP_PROT_WRITE);
414           SOS_ASSERT_FATAL(retval == SOS_OK);
415 
416           retval = sos_physmem_unref_physpage(ppage);
417           SOS_ASSERT_FATAL(retval == 0);
418         }
419 
420       /* Copy segment into memory */
421       memcpy((void*) elf_phdrs[i].p_vaddr,
422              (void*) (prog->bottom_vaddr + elf_phdrs[i].p_offset),
423              elf_phdrs[i].p_filesz);
424     }
425 
426   return elf_hdr->e_entry;
427 }

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