aout_loader.c

Go to the documentation of this file.
00001 /* a.out */
00002 struct exec {
00003         unsigned long      a_midmag;    /* flags<<26 | mid<<16 | magic */
00004         unsigned long      a_text;      /* text segment size */
00005         unsigned long      a_data;      /* initialized data size */
00006         unsigned long      a_bss;       /* uninitialized data size */
00007         unsigned long      a_syms;      /* symbol table size */
00008         unsigned long      a_entry;     /* entry point */
00009         unsigned long      a_trsize;    /* text relocation size */
00010         unsigned long      a_drsize;    /* data relocation size */
00011 };
00012 
00013 struct aout_state {
00014         struct exec head;
00015         unsigned long curaddr;
00016         int segment;                    /* current segment number, -1 for none */
00017         unsigned long loc;              /* start offset of current block */
00018         unsigned long skip;             /* padding to be skipped to current segment */
00019         unsigned long toread;           /* remaining data to be read in the segment */
00020 };
00021 
00022 static struct aout_state astate;
00023 
00024 static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
00025 static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
00026 {
00027         unsigned long start, mid, end, istart, iend;
00028         if (len < sizeof(astate.head)) {
00029                 return 0;
00030         }
00031         memcpy(&astate.head, data, sizeof(astate.head));
00032         if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
00033                 return 0;
00034         }
00035         
00036         printf("(a.out");
00037         aout_freebsd_probe();
00038         printf(")... ");
00039         /* Check the aout image */
00040         start  = astate.head.a_entry;
00041         mid    = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
00042         end    = ((mid + 4095) & ~4095) + astate.head.a_bss;
00043         istart = 4096;
00044         iend   = istart + (mid - start);
00045         if (!prep_segment(start, mid, end, istart, iend))
00046                 return dead_download;
00047         astate.segment = -1;
00048         astate.loc = 0;
00049         astate.skip = 0;
00050         astate.toread = 0;
00051         return aout_download;
00052 }
00053 
00054 static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
00055 {
00056         unsigned int offset;    /* working offset in the current data block */
00057 
00058         offset = 0;
00059 
00060 #ifdef AOUT_LYNX_KDI
00061         astate.segment++;
00062         if (astate.segment == 0) {
00063                 astate.curaddr = 0x100000;
00064                 astate.head.a_entry = astate.curaddr + 0x20;
00065         }
00066         memcpy(phys_to_virt(astate.curaddr), data, len);
00067         astate.curaddr += len;
00068         return 0;
00069 #endif
00070 
00071         do {
00072                 if (astate.segment != -1) {
00073                         if (astate.skip) {
00074                                 if (astate.skip >= len - offset) {
00075                                         astate.skip -= len - offset;
00076                                         break;
00077                                 }
00078                                 offset += astate.skip;
00079                                 astate.skip = 0;
00080                         }
00081 
00082                         if (astate.toread) {
00083                                 if (astate.toread >= len - offset) {
00084                                         memcpy(phys_to_virt(astate.curaddr), data+offset,
00085                                                 len - offset);
00086                                         astate.curaddr += len - offset;
00087                                         astate.toread -= len - offset;
00088                                         break;
00089                                 }
00090                                 memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
00091                                 offset += astate.toread;
00092                                 astate.toread = 0;
00093                         }
00094                 }
00095 
00096                 /* Data left, but current segment finished - look for the next
00097                  * segment.  This is quite simple for a.out files.  */
00098                 astate.segment++;
00099                 switch (astate.segment) {
00100                 case 0:
00101                         /* read text */
00102                         astate.curaddr = astate.head.a_entry;
00103                         astate.skip = 4096;
00104                         astate.toread = astate.head.a_text;
00105                         break;
00106                 case 1:
00107                         /* read data */
00108                         /* skip and curaddr may be wrong, but I couldn't find
00109                          * examples where this failed.  There is no reasonable
00110                          * documentation for a.out available.  */
00111                         astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
00112                         astate.curaddr = (astate.curaddr + 4095) & ~4095;
00113                         astate.toread = astate.head.a_data;
00114                         break;
00115                 case 2:
00116                         /* initialize bss and start kernel */
00117                         astate.curaddr = (astate.curaddr + 4095) & ~4095;
00118                         astate.skip = 0;
00119                         astate.toread = 0;
00120                         memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
00121                         goto aout_startkernel;
00122                 default:
00123                         break;
00124                 }
00125         } while (offset < len);
00126 
00127         astate.loc += len;
00128 
00129         if (eof) {
00130                 unsigned long entry;
00131 
00132 aout_startkernel:
00133                 entry = astate.head.a_entry;
00134                 done(1);
00135 
00136                 aout_freebsd_boot();
00137 #ifdef AOUT_LYNX_KDI
00138                 xstart32(entry);
00139 #endif
00140                 printf("unexpected a.out variant\n");
00141                 longjmp(restart_etherboot, -2);
00142         }
00143         return 0;
00144 }

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