freebsd_loader.c

Go to the documentation of this file.
00001 /* bootinfo */
00002 #define BOOTINFO_VERSION 1
00003 #define NODEV           (-1)    /* non-existent device */
00004 #define PAGE_SHIFT      12              /* LOG2(PAGE_SIZE) */
00005 #define PAGE_SIZE       (1<<PAGE_SHIFT) /* bytes/page */
00006 #define PAGE_MASK       (PAGE_SIZE-1)
00007 #define N_BIOS_GEOM     8
00008 
00009 struct bootinfo {
00010         unsigned int            bi_version;
00011         const unsigned char     *bi_kernelname;
00012         struct nfs_diskless     *bi_nfs_diskless;
00013                                 /* End of fields that are always present. */
00014 #define bi_endcommon            bi_n_bios_used
00015         unsigned int            bi_n_bios_used;
00016         unsigned long           bi_bios_geom[N_BIOS_GEOM];
00017         unsigned int            bi_size;
00018         unsigned char           bi_memsizes_valid;
00019         unsigned char           bi_pad[3];
00020         unsigned long           bi_basemem;
00021         unsigned long           bi_extmem;
00022         unsigned long           bi_symtab;
00023         unsigned long           bi_esymtab;
00024         /* Note that these are in the FreeBSD headers but were not here... */
00025         unsigned long           bi_kernend;             /* end of kernel space */
00026         unsigned long           bi_envp;                /* environment */
00027         unsigned long           bi_modulep;             /* preloaded modules */
00028 };
00029 
00030 static struct bootinfo bsdinfo;
00031 
00032 #ifdef ELF_IMAGE
00033 static Elf32_Shdr *shdr;        /* To support the FreeBSD kludge! */
00034 static Address symtab_load;
00035 static Address symstr_load;
00036 static int symtabindex;
00037 static int symstrindex;
00038 #endif
00039 
00040 static enum {
00041         Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD,
00042 } image_type = Unknown;
00043 
00044 static unsigned int off;
00045 
00046 
00047 #ifdef ELF_IMAGE
00048 static void elf_freebsd_probe(void)
00049 {
00050         image_type = Elf;
00051         if (    (estate.e.elf32.e_entry & 0xf0000000) && 
00052                 (estate.e.elf32.e_type == ET_EXEC))
00053         {
00054                 image_type = Elf_FreeBSD;
00055                 printf("/FreeBSD");
00056                 off = -(estate.e.elf32.e_entry & 0xff000000);
00057                 estate.e.elf32.e_entry += off;
00058         }
00059         /* Make sure we have a null to start with... */
00060         shdr = 0;
00061         
00062         /* Clear the symbol index values... */
00063         symtabindex = -1;
00064         symstrindex = -1;
00065         
00066         /* ...and the load addresses of the symbols  */
00067         symtab_load = 0;
00068         symstr_load = 0;
00069 }
00070 
00071 static void elf_freebsd_fixup_segment(void)
00072 {
00073         if (image_type == Elf_FreeBSD) {
00074                 estate.p.phdr32[estate.segment].p_paddr += off;
00075         }
00076 }
00077 
00078 static void elf_freebsd_find_segment_end(void)
00079 {
00080         /* Count the bytes read even for the last block
00081          * as we will need to know where the last block
00082          * ends in order to load the symbols correctly.
00083          * (plus it could be useful elsewhere...)
00084          * Note that we need to count the actual size,
00085          * not just the end of the disk image size.
00086          */
00087         estate.curaddr += 
00088                 (estate.p.phdr32[estate.segment].p_memsz - 
00089                 estate.p.phdr32[estate.segment].p_filesz);
00090 }
00091 
00092 static int elf_freebsd_debug_loader(unsigned int offset)
00093 {
00094         /* No more segments to be loaded - time to start the
00095          * nasty state machine to support the loading of
00096          * FreeBSD debug symbols due to the fact that FreeBSD
00097          * uses/exports the kernel's debug symbols in order
00098          * to make much of the system work!  Amazing (arg!)
00099          *
00100          * We depend on the fact that for the FreeBSD kernel,
00101          * there is only one section of debug symbols and that
00102          * the section is after all of the loaded sections in
00103          * the file.  This assumes a lot but is somewhat required
00104          * to make this code not be too annoying.  (Where do you
00105          * load symbols when the code has not loaded yet?)
00106          * Since this function is actually just a callback from
00107          * the network data transfer code, we need to be able to
00108          * work with the data as it comes in.  There is no chance
00109          * for doing a seek other than forwards.
00110          *
00111          * The process we use is to first load the section
00112          * headers.  Once they are loaded (shdr != 0) we then
00113          * look for where the symbol table and symbol table
00114          * strings are and setup some state that we found
00115          * them and fall into processing the first one (which
00116          * is the symbol table) and after that has been loaded,
00117          * we try the symbol strings.  Note that the order is
00118          * actually required as the memory image depends on
00119          * the symbol strings being loaded starting at the
00120          * end of the symbol table.  The kernel assumes this
00121          * layout of the image.
00122          *
00123          * At any point, if we get to the end of the load file
00124          * or the section requested is earlier in the file than
00125          * the current file pointer, we just end up falling
00126          * out of this and booting the kernel without this
00127          * information.
00128          */
00129 
00130         /* Make sure that the next address is long aligned... */
00131         /* Assumes size of long is a power of 2... */
00132         estate.curaddr = (estate.curaddr + sizeof(long) - 1) & ~(sizeof(long) - 1);
00133         
00134         /* If we have not yet gotten the shdr loaded, try that */
00135         if (shdr == 0)
00136         {
00137                 estate.toread = estate.e.elf32.e_shnum * estate.e.elf32.e_shentsize;
00138                 estate.skip = estate.e.elf32.e_shoff - (estate.loc + offset);
00139                 if (estate.toread)
00140                 {
00141 #if ELF_DEBUG
00142                         printf("shdr *, size %lX, curaddr %lX\n", 
00143                                 estate.toread, estate.curaddr);
00144 #endif
00145                         
00146                         /* Start reading at the curaddr and make that the shdr */
00147                         shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr);
00148                         
00149                         /* Start to read... */
00150                         return 1;
00151                 }
00152         }
00153         else
00154         {
00155                 /* We have the shdr loaded, check if we have found
00156                  * the indexs where the symbols are supposed to be */
00157                 if ((symtabindex == -1) && (symstrindex == -1))
00158                 {
00159                         int i;
00160                         /* Make sure that the address is page aligned... */
00161                         /* Symbols need to start in their own page(s)... */
00162                         estate.curaddr = (estate.curaddr + 4095) & ~4095;
00163                         
00164                         /* Need to make new indexes... */
00165                         for (i=0; i < estate.e.elf32.e_shnum; i++)
00166                         {
00167                                 if (shdr[i].sh_type == SHT_SYMTAB)
00168                                 {
00169                                         int j;
00170                                         for (j=0; j < estate.e.elf32.e_phnum; j++)
00171                                         {
00172                                                 /* Check only for loaded sections */
00173                                                 if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80))
00174                                                 {
00175                                                         /* Only the extra symbols */
00176                                                         if ((shdr[i].sh_offset >= estate.p.phdr32[j].p_offset) &&
00177                                                                 ((shdr[i].sh_offset + shdr[i].sh_size) <=
00178                                                                         (estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz)))
00179                                                         {
00180                                                                 shdr[i].sh_offset=0;
00181                                                                 shdr[i].sh_size=0;
00182                                                                 break;
00183                                                         }
00184                                                 }
00185                                         }
00186                                         if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0))
00187                                         {
00188                                                 symtabindex = i;
00189                                                 symstrindex = shdr[i].sh_link;
00190                                         }
00191                                 }
00192                         }
00193                 }
00194                 
00195                 /* Check if we have a symbol table index and have not loaded it */
00196                 if ((symtab_load == 0) && (symtabindex >= 0))
00197                 {
00198                         /* No symbol table yet?  Load it first... */
00199                         
00200                         /* This happens to work out in a strange way.
00201                          * If we are past the point in the file already,
00202                          * we will skip a *large* number of bytes which
00203                          * ends up bringing us to the end of the file and
00204                          * an old (default) boot.  Less code and lets
00205                          * the state machine work in a cleaner way but this
00206                          * is a nasty side-effect trick... */
00207                         estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset);
00208                         
00209                         /* And we need to read this many bytes... */
00210                         estate.toread = shdr[symtabindex].sh_size;
00211                         
00212                         if (estate.toread)
00213                         {
00214 #if ELF_DEBUG
00215                                 printf("db sym, size %lX, curaddr %lX\n", 
00216                                         estate.toread, estate.curaddr);
00217 #endif
00218                                 /* Save where we are loading this... */
00219                                 symtab_load = estate.curaddr;
00220                                 
00221                                 *((long *)phys_to_virt(estate.curaddr)) = estate.toread;
00222                                 estate.curaddr += sizeof(long);
00223                                 
00224                                 /* Start to read... */
00225                                 return 1;
00226                         }
00227                 }
00228                 else if ((symstr_load == 0) && (symstrindex >= 0))
00229                 {
00230                         /* We have already loaded the symbol table, so
00231                          * now on to the symbol strings... */
00232                         
00233                         
00234                         /* Same nasty trick as above... */
00235                         estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset);
00236                         
00237                         /* And we need to read this many bytes... */
00238                         estate.toread = shdr[symstrindex].sh_size;
00239                         
00240                         if (estate.toread)
00241                         {
00242 #if ELF_DEBUG
00243                                 printf("db str, size %lX, curaddr %lX\n", 
00244                                         estate.toread, estate.curaddr);
00245 #endif
00246                                 /* Save where we are loading this... */
00247                                 symstr_load = estate.curaddr;
00248                                 
00249                                 *((long *)phys_to_virt(estate.curaddr)) = estate.toread;
00250                                 estate.curaddr += sizeof(long);
00251                                 
00252                                 /* Start to read... */
00253                                 return 1;
00254                         }
00255                 }
00256         }
00257         /* all done */
00258         return 0;
00259 }
00260 
00261 static void elf_freebsd_boot(unsigned long entry) 
00262 {
00263         if (image_type != Elf_FreeBSD)
00264                 return;
00265 
00266         memset(&bsdinfo, 0, sizeof(bsdinfo));
00267         bsdinfo.bi_basemem = meminfo.basememsize;
00268         bsdinfo.bi_extmem = meminfo.memsize;
00269         bsdinfo.bi_memsizes_valid = 1;
00270         bsdinfo.bi_version = BOOTINFO_VERSION;
00271         bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
00272         bsdinfo.bi_nfs_diskless = NULL;
00273         bsdinfo.bi_size = sizeof(bsdinfo);
00274 #define RB_BOOTINFO     0x80000000      /* have `struct bootinfo *' arg */  
00275         if(freebsd_kernel_env[0] != '\0'){
00276                 freebsd_howto |= RB_BOOTINFO;
00277                 bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env;
00278         }
00279         
00280         /* Check if we have symbols loaded, and if so,
00281          * made the meta_data needed to pass those to
00282          * the kernel. */
00283         if ((symtab_load !=0) && (symstr_load != 0))
00284         {
00285                 unsigned long *t;
00286                 
00287                 bsdinfo.bi_symtab = symtab_load;
00288                 
00289                 /* End of symbols (long aligned...) */
00290                 /* Assumes size of long is a power of 2... */
00291                 bsdinfo.bi_esymtab = (symstr_load +
00292                         sizeof(long) +
00293                         *((long *)phys_to_virt(symstr_load)) +
00294                         sizeof(long) - 1) & ~(sizeof(long) - 1);
00295                 
00296                 /* Where we will build the meta data... */
00297                 t = phys_to_virt(bsdinfo.bi_esymtab);
00298                 
00299 #if ELF_DEBUG
00300                 printf("Metadata at %lX\n",t);
00301 #endif
00302                 
00303                 /* Set up the pointer to the memory... */
00304                 bsdinfo.bi_modulep = virt_to_phys(t);
00305                 
00306                 /* The metadata structure is an array of 32-bit
00307                  * words where we store some information about the
00308                  * system.  This is critical, as FreeBSD now looks
00309                  * only for the metadata for the extended symbol
00310                  * information rather than in the bootinfo.
00311                  */
00312                 /* First, do the kernel name and the kernel type */
00313                 /* Note that this assumed x86 byte order... */
00314                 
00315                 /* 'kernel\0\0' */
00316                 *t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65;
00317                 
00318                 /* 'elf kernel\0\0' */
00319                 *t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65;
00320                 
00321                 /* Now the symbol start/end - note that they are
00322                  * here in local/physical address - the Kernel
00323                  * boot process will relocate the addresses. */
00324                 *t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab;
00325                 *t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab;
00326                 
00327                 *t++=MODINFO_END; *t++=0; /* end of metadata */
00328                 
00329                 /* Since we have symbols we need to make
00330                  * sure that the kernel knows its own end
00331                  * of memory...  It is not _end but after
00332                  * the symbols and the metadata... */
00333                 bsdinfo.bi_kernend = virt_to_phys(t);
00334                 
00335                 /* Signal locore.s that we have a valid bootinfo
00336                  * structure that was completely filled in. */
00337                 freebsd_howto |= 0x80000000;
00338         }
00339         
00340         xstart32(entry, freebsd_howto, NODEV, 0, 0, 0, 
00341                 virt_to_phys(&bsdinfo), 0, 0, 0);
00342         longjmp(restart_etherboot, -2);
00343 }
00344 #endif
00345 
00346 #ifdef AOUT_IMAGE
00347 static void aout_freebsd_probe(void)
00348 {
00349         image_type = Aout;
00350         if (((astate.head.a_midmag >> 16) & 0xffff) == 0) {
00351                 /* Some other a.out variants have a different
00352                  * value, and use other alignments (e.g. 1K),
00353                  * not the 4K used by FreeBSD.  */
00354                 image_type = Aout_FreeBSD;
00355                 printf("/FreeBSD");
00356                 off = -(astate.head.a_entry & 0xff000000);
00357                 astate.head.a_entry += off;
00358         }
00359 }
00360 
00361 static void aout_freebsd_boot(void)
00362 {
00363         if (image_type == Aout_FreeBSD) {
00364                 memset(&bsdinfo, 0, sizeof(bsdinfo));
00365                 bsdinfo.bi_basemem = meminfo.basememsize;
00366                 bsdinfo.bi_extmem = meminfo.memsize;
00367                 bsdinfo.bi_memsizes_valid = 1;
00368                 bsdinfo.bi_version = BOOTINFO_VERSION;
00369                 bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
00370                 bsdinfo.bi_nfs_diskless = NULL;
00371                 bsdinfo.bi_size = sizeof(bsdinfo);
00372                 xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0, 
00373                         virt_to_phys(&bsdinfo), 0, 0, 0);
00374                 longjmp(restart_etherboot, -2);
00375         }
00376 }
00377 #endif

Generated on Tue Apr 6 20:00:49 2010 for gPXE by  doxygen 1.5.7.1