Home | History | Annotate | Download | only in core
      1 /* a.out */
      2 struct exec {
      3 	unsigned long      a_midmag;	/* flags<<26 | mid<<16 | magic */
      4 	unsigned long      a_text;	/* text segment size */
      5 	unsigned long      a_data;	/* initialized data size */
      6 	unsigned long      a_bss;	/* uninitialized data size */
      7 	unsigned long      a_syms;	/* symbol table size */
      8 	unsigned long      a_entry;	/* entry point */
      9 	unsigned long      a_trsize;	/* text relocation size */
     10 	unsigned long      a_drsize;	/* data relocation size */
     11 };
     12 
     13 struct aout_state {
     14 	struct exec head;
     15 	unsigned long curaddr;
     16 	int segment;			/* current segment number, -1 for none */
     17 	unsigned long loc;		/* start offset of current block */
     18 	unsigned long skip;		/* padding to be skipped to current segment */
     19 	unsigned long toread;		/* remaining data to be read in the segment */
     20 };
     21 
     22 static struct aout_state astate;
     23 
     24 static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
     25 static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
     26 {
     27 	unsigned long start, mid, end, istart, iend;
     28 	if (len < sizeof(astate.head)) {
     29 		return 0;
     30 	}
     31 	memcpy(&astate.head, data, sizeof(astate.head));
     32 	if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
     33 		return 0;
     34 	}
     35 
     36 	printf("(a.out");
     37 	aout_freebsd_probe();
     38 	printf(")... ");
     39 	/* Check the aout image */
     40 	start  = astate.head.a_entry;
     41 	mid    = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
     42 	end    = ((mid + 4095) & ~4095) + astate.head.a_bss;
     43 	istart = 4096;
     44 	iend   = istart + (mid - start);
     45 	if (!prep_segment(start, mid, end, istart, iend))
     46 		return dead_download;
     47 	astate.segment = -1;
     48 	astate.loc = 0;
     49 	astate.skip = 0;
     50 	astate.toread = 0;
     51 	return aout_download;
     52 }
     53 
     54 static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
     55 {
     56 	unsigned int offset;	/* working offset in the current data block */
     57 
     58 	offset = 0;
     59 
     60 #ifdef AOUT_LYNX_KDI
     61 	astate.segment++;
     62 	if (astate.segment == 0) {
     63 		astate.curaddr = 0x100000;
     64 		astate.head.a_entry = astate.curaddr + 0x20;
     65 	}
     66 	memcpy(phys_to_virt(astate.curaddr), data, len);
     67 	astate.curaddr += len;
     68 	return 0;
     69 #endif
     70 
     71 	do {
     72 		if (astate.segment != -1) {
     73 			if (astate.skip) {
     74 				if (astate.skip >= len - offset) {
     75 					astate.skip -= len - offset;
     76 					break;
     77 				}
     78 				offset += astate.skip;
     79 				astate.skip = 0;
     80 			}
     81 
     82 			if (astate.toread) {
     83 				if (astate.toread >= len - offset) {
     84 					memcpy(phys_to_virt(astate.curaddr), data+offset,
     85 						len - offset);
     86 					astate.curaddr += len - offset;
     87 					astate.toread -= len - offset;
     88 					break;
     89 				}
     90 				memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
     91 				offset += astate.toread;
     92 				astate.toread = 0;
     93 			}
     94 		}
     95 
     96 		/* Data left, but current segment finished - look for the next
     97 		 * segment.  This is quite simple for a.out files.  */
     98 		astate.segment++;
     99 		switch (astate.segment) {
    100 		case 0:
    101 			/* read text */
    102 			astate.curaddr = astate.head.a_entry;
    103 			astate.skip = 4096;
    104 			astate.toread = astate.head.a_text;
    105 			break;
    106 		case 1:
    107 			/* read data */
    108 			/* skip and curaddr may be wrong, but I couldn't find
    109 			 * examples where this failed.  There is no reasonable
    110 			 * documentation for a.out available.  */
    111 			astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
    112 			astate.curaddr = (astate.curaddr + 4095) & ~4095;
    113 			astate.toread = astate.head.a_data;
    114 			break;
    115 		case 2:
    116 			/* initialize bss and start kernel */
    117 			astate.curaddr = (astate.curaddr + 4095) & ~4095;
    118 			astate.skip = 0;
    119 			astate.toread = 0;
    120 			memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
    121 			goto aout_startkernel;
    122 		default:
    123 			break;
    124 		}
    125 	} while (offset < len);
    126 
    127 	astate.loc += len;
    128 
    129 	if (eof) {
    130 		unsigned long entry;
    131 
    132 aout_startkernel:
    133 		entry = astate.head.a_entry;
    134 		done(1);
    135 
    136 		aout_freebsd_boot();
    137 #ifdef AOUT_LYNX_KDI
    138 		xstart32(entry);
    139 #endif
    140 		printf("unexpected a.out variant\n");
    141 		longjmp(restart_etherboot, -2);
    142 	}
    143 	return 0;
    144 }
    145