1/* a.out */ 2struct 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 13struct 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 22static struct aout_state astate; 23 24static sector_t aout_download(unsigned char *data, unsigned int len, int eof); 25static 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 54static 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 132aout_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