wok-next view syslinux/stuff/iso2exe/bootlinux.c @ rev 15980
syslinux/iso2exe: skip 15M-16M frequent hole
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Sat Mar 01 10:30:44 2014 +0000 (2014-03-01) |
parents | 19258b949c1b |
children | 3f0b08dbc9d3 |
line source
1 #include <stdio.h>
2 #include "iso9660.h"
4 static unsigned version;
5 #define SETUPSECTORS 0x1F1
6 #define ROFLAG 0x1F2
7 #define SYSSIZE 0x1F4
8 #define VIDEOMODE 0x1FA
9 #define BOOTFLAG 0x1FE
10 #define HEADER 0x202
11 #define VERSION 0x206
12 #define RMSWOFS 0x208
13 #define RMSWSEG 0x20A
14 #define LOADERTYPE 0x210
15 #define LOADFLAGS 0x211
16 #define SYSTEMCODE 0x214
17 #define INITRDCODE 0x218
18 #define INITRDSIZE 0x21C
19 #define HEAPPTR 0x224
20 #define CMDLINE 0x228
22 #define SETUP_SEGMENT 0x9000
23 #define CMDLINE_OFFSET 0x9E00
25 #define PAGE_BITS 12
26 #define PAGE_SIZE 4096
27 #define BUFFERSZ PAGE_SIZE
28 static char buffer[BUFFERSZ];
29 static unsigned long initrd_addr, initrd_size;
31 static int may_exit_dos = 1;
32 static void die(char *msg)
33 {
34 printf("%s.\n", msg);
35 if (may_exit_dos)
36 exit(1);
37 while (1);
38 }
40 static int vm86(void)
41 {
42 #asm
43 smsw ax
44 and ax, #1 // 0:realmode 1:vm86
45 #endasm
46 }
48 static struct mem {
49 unsigned long base;
50 int align;
51 } kernelmem = { 0x100000, 0 };
53 #define initrdmem kernelmem
55 static void movehi(void)
56 {
57 #asm
58 pusha
59 xor di, di // 30
60 mov cx, #9 // 2E..1E
61 zero1:
62 push di
63 loop zero1
64 push dword [_kernelmem] // 1A p->base
65 push #-1 // 18
66 push di // 16
67 xor eax, eax
68 cdq
69 mov dx, ds
70 shl edx, #4
71 mov ax, #_buffer
72 add edx, eax
73 push edx // 12 linear_address(buffer)
74 push #-1 // 10
75 mov cl, #8 // 0E..00
76 zero2:
77 push di
78 loop zero2
79 mov ch, #BUFFERSZ/512
80 push ss
81 pop es
82 mov si, sp
83 mov ax, #0x8793
84 mov [si+0x15], al
85 xchg [si+0x1D], al
86 mov [si+0x1F], al // bits 24..31
87 int 0x15
88 add sp, #0x30
89 popa
90 #endasm
91 }
93 #undef ZIMAGE_SUPPORT /* Does not work... */
95 static int versiondos;
96 static int dosversion(void)
97 {
98 #asm
99 mov ah, #0x30
100 int 0x21
101 cbw
102 mov _versiondos, ax
103 #endasm
104 }
106 static void load(struct mem *p, unsigned long size)
107 {
108 if (vm86())
109 die("Need real mode");
110 switch (p->align) {
111 case 0: // kernel
112 switch (dosversion()) {
113 case 3: case 4: case 6: break;
114 default:
115 printf("DOS %d not supported.\nTrying anyway...\n",
116 versiondos);
117 }
118 p->align = PAGE_SIZE;
119 break;
120 case 4096: // first initrd : skip 0xF00000 .. 0x1000000 mapping hole
121 initrd_addr = (p->base + size > 0xF00000 &&
122 p->base < 0x1000000) ? 0x1000000 : p->base;
123 p->align = 4;
124 }
125 while (size) {
126 int n, s = sizeof(buffer);
127 for (n = 0; n < s; n++) buffer[n] = 0;
128 if (s > size) s = size;
129 n = isoread(buffer, s);
130 movehi();
131 if (n != -1) {
132 p->base += n;
133 size -= n;
134 }
135 if (s != n) break;
136 }
137 initrd_size = p->base - initrd_addr;
138 p->base += p->align - 1;
139 p->base &= - p->align;
140 }
142 static unsigned setupofs = 0;
144 void movesetup(void)
145 {
146 #asm
147 pusha
148 push #SETUP_SEGMENT
149 pop es
150 mov si, #_buffer
151 mov di, _setupofs
152 mov cx, #BUFFERSZ/2
153 rep
154 movsw
155 mov _setupofs, di
156 popa
157 #endasm
158 }
160 static unsigned getcs(void)
161 {
162 #asm
163 mov ax, cs
164 #endasm
165 }
167 unsigned long loadkernel(void)
168 {
169 unsigned setup, n = BUFFERSZ;
170 unsigned long syssize = 0, kernel_version = 0;
172 do {
173 isoread(buffer, n);
174 if (setupofs == 0) {
175 if (* (unsigned short *) (buffer + BOOTFLAG) != 0xAA55)
176 die("The kernel is not bootable");
177 setup = (1 + buffer[SETUPSECTORS]) << 9;
178 if (setup == 512) setup = 5 << 9;
179 syssize = * (unsigned long *) (buffer + SYSSIZE) << 4;
180 version = * (unsigned short *) (buffer + VERSION);
181 #define HDRS 0x53726448
182 if (* (unsigned long *) (buffer + HEADER) != HDRS)
183 version = 0;
184 if (version < 0x204)
185 syssize &= 0x000FFFFFUL;
186 if (version) {
187 #ifdef REALMODE_SWITCH
188 extern int far_realmode_switch();
189 #asm
190 jmp end_realmode_switch
191 _far_realmode_switch:
192 call REALMODE_SWITCH
193 cli
194 mov al, #0x80 // Disable NMI
195 out 0x70, al
196 retf
197 end_realmode_switch:
198 #endasm
199 * (unsigned short *) (buffer + RMSWOFS) =
200 far_realmode_switch;
201 * (unsigned short *) (buffer + RMSWSEG) =
202 getcs();
203 #endif
204 kernelmem.base =
205 * (unsigned long *) (buffer + SYSTEMCODE);
206 * (unsigned short *) (buffer + HEAPPTR) =
207 0x9B00;
208 // buffer[LOADFLAGS] |= 0x80;
209 * (unsigned short *) (buffer + LOADERTYPE) |=
210 0x80FF;
211 }
212 if (!version || !(buffer[LOADFLAGS] & 1)) {
213 #ifdef ZIMAGE_SUPPORT
214 #asm
215 pusha
216 mov cx, #0x8000
217 mov es, cx
218 xor si, si
219 xor di, di
220 rep
221 movsw // move 64K data
222 push es
223 pop ds
224 push es
225 pop ss
226 mov ch, #0x70
227 mov es, cx
228 mov ch, #0x80
229 rep
230 seg cs
231 movsw // move 64K code
232 popa
233 jmpi relocated, #0x7000
234 relocated:
235 #endasm
236 kernelmem.base = 0x10000;
237 if (syssize > 0x60000) /* 384K max */
238 #endif
239 die("Not a bzImage format");
240 }
241 }
242 movesetup();
243 setup -= n;
244 n = (setup > BUFFERSZ) ? BUFFERSZ : setup;
245 } while (setup > 0);
247 #asm
248 push ds
249 push #SETUP_SEGMENT
250 pop ds
251 mov si, #0x200
252 mov eax, #0x53726448 // HdrS
253 cdq // clear edx
254 cmp [si+2], eax
255 jne noversion
256 add si, [si+14]
257 mov cx, #3
258 xor ax, ax
259 nextdigit:
260 shl al, #4
261 shl ax, #4
262 next:
263 lodsb
264 sub al, #0x30
265 cmp al, #9
266 jbe nextdigit
267 shl eax, #16
268 shld edx, eax, #8
269 loop next
270 pop ds
271 mov .loadkernel.kernel_version[bp], edx
272 noversion:
273 #endasm
274 load(&kernelmem, syssize);
275 return kernel_version;
276 }
278 void loadinitrd(void)
279 {
280 if (version)
281 load(&initrdmem, isofilesize);
282 }
284 void bootlinux(char *cmdline)
285 {
286 #asm
287 push #SETUP_SEGMENT
288 pop es
289 mov eax, _initrd_addr
290 or eax, eax
291 jz no_initrd
292 mov di, #0x218
293 stosd
294 mov eax, _initrd_size
295 stosd
296 no_initrd:
297 #endasm
298 if (cmdline) {
299 if (version <= 0x201) {
300 #asm
301 mov di, #0x0020
302 mov ax, #0xA33F
303 stosw
304 mov ax, #CMDLINE_OFFSET
305 stosw
306 #endasm
307 }
308 else {
309 #asm
310 mov di, #0x0228
311 mov eax, #SETUP_SEGMENT*16+CMDLINE_OFFSET
312 stosd
313 #endasm
314 }
315 #asm
316 xchg ax, di
317 mov si, .bootlinux.cmdline[bp]
318 copy:
319 lodsb
320 stosb
321 or al,al
322 jne copy
323 #endasm
324 }
325 #asm
326 push es
327 pop ds
328 push ds
329 pop ss
330 mov sp, #CMDLINE_OFFSET
331 jmpi 0, #0x9020
332 #endasm
333 }