• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
aout_probe(unsigned char * data,unsigned int len)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 
aout_download(unsigned char * data,unsigned int len,int eof)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