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