wok-6.x view syslinux/stuff/iso2exe/bootlinux.c @ rev 17161
syslinux/iso2exe: full zImage support (again)
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Wed Sep 17 15:21:35 2014 +0200 (2014-09-17) |
parents | 3e7ad70145ce |
children | 799c2ec31b04 |
line source
1 #include <stdio.h>
2 #include "libdos.h"
3 #include "iso9660.h"
5 static unsigned setup_version;
6 #define ELKSSIG 0x1E6
7 #define SETUPSECTORS 0x1F1
8 #define ROFLAG 0x1F2
9 #define SYSSIZE 0x1F4
10 #define VIDEOMODE 0x1FA
11 #define BOOTFLAG 0x1FE
12 #define HEADER 0x202
13 #define VERSION 0x206
14 #define RMSWOFS 0x208
15 #define RMSWSEG 0x20A
16 #define LOADERTYPE 0x210
17 #define LOADFLAGS 0x211
18 #define SYSTEMCODE 0x214
19 #define INITRDCODE 0x218
20 #define INITRDSIZE 0x21C
21 #define HEAPPTR 0x224
22 #define CMDLINE 0x228
24 #define SYSTEM_SEGMENT 0x1000
25 #define SETUP_SEGMENT 0x9000
26 #define CMDLINE_OFFSET 0x9E00
27 #define SETUP_END 0x8200
29 #define PAGE_BITS 12
30 #define PAGE_SIZE 4096
31 #define BUFFERSZ 2048 // lower than min setup
32 static char buffer[BUFFERSZ];
33 static unsigned long initrd_addr = 0, initrd_size;
35 static int may_exit_dos = 1;
36 static void die(char *msg)
37 {
38 printf("%s.\n", msg);
39 if (may_exit_dos)
40 exit(1);
41 while (1);
42 }
44 static int iselks;
45 static int vm86(void)
46 {
47 #asm
48 xor ax, ax
49 cmp ax, _iselks
50 jne fakerealmode // elks may run on a 8086
51 smsw ax // 286+
52 and ax, #1 // 0:realmode 1:vm86
53 fakerealmode:
54 #endasm
55 }
57 static struct {
58 unsigned long base;
59 int align;
60 } mem = { 0x100000, 0 };
62 static void movehi(void)
63 {
64 #asm
65 push si
66 push di
68 mov si, #_mem
69 cmp word ptr [si+2], #0x10
70 jnc movehiz
71 mov ax, [si+1]
72 mov cl, #4
73 shl ax, cl // 8086 support for elks
74 mov es, ax
75 mov di, #0x00FF
76 and di, [si]
77 mov si, #_buffer
78 mov cx, #BUFFERSZ/2
79 cld
80 rep
81 movw
82 jmp movedone
83 movehiz:
84 xor di, di // 30
85 mov cx, #9 // 2E..1E
86 zero1:
87 push di
88 loop zero1
89 push dword [si] // 1A mem.base
90 push #-1 // 18
91 push di // 16
92 xor eax, eax
93 cdq
94 mov dx, ds
95 shl edx, #4
96 mov ax, #_buffer
97 add edx, eax
98 push edx // 12 linear_address(buffer)
99 push #-1 // 10
100 mov cl, #8 // 0E..00
101 zero2:
102 push di
103 loop zero2
104 mov ch, #BUFFERSZ/512
105 push ss
106 pop es
107 mov si, sp
108 mov ax, #0x8793
109 mov [si+0x15], al
110 xchg [si+0x1D], al
111 xchg [si+0x1F], al // bits 24..31
112 int 0x15
113 add sp, #0x30
114 movedone:
115 pop di
116 pop si
117 #endasm
118 }
120 #define ZIMAGE_SUPPORT
121 #define FULL_ZIMAGE
123 #ifdef ZIMAGE_SUPPORT
124 static unsigned zimage = 0;
125 static unsigned getss(void)
126 {
127 #asm
128 mov ax, ss
129 #endasm
130 }
131 #endif
133 static unsigned extendedramsizeinkb(void)
134 {
135 #asm
136 mov ah, #0x88
137 int 0x15
138 jnc gottop
139 xor ax, ax
140 gottop:
141 #endasm
142 }
145 #include "a20.c"
147 static void load(unsigned long size)
148 {
149 if (vm86())
150 die("Need real mode");
151 switch (mem.align) {
152 case 0: // kernel
153 #ifdef __MSDOS__
154 if ((unsigned) (dosversion() - 3) > 7 - 3) {
155 printf("DOS %d not supported.\nTrying anyway...\n",
156 versiondos);
157 }
158 #endif
159 mem.align = PAGE_SIZE;
160 break;
161 case PAGE_SIZE: // first initrd : keep 16M..48M for the kernel
162 if (extendedramsizeinkb() > 0xF000U && mem.base < 0x3000000)
163 mem.base = 0x3000000;
164 initrd_addr = mem.base;
165 mem.align = 4;
166 }
167 #ifdef ALLOCMEM
168 ALLOCMEM(size);
169 #endif
170 while (size) {
171 int n, s = sizeof(buffer);
172 for (n = 0; n < s; n++) buffer[n] = 0;
173 if (s > size) s = size;
174 if ((n = isoread(buffer, s)) < 0) break;
175 movehi();
176 mem.base += n;
177 size -= n;
178 if (s != n) break; // end of file
179 }
180 initrd_size = mem.base - initrd_addr;
181 mem.base += mem.align - 1;
182 mem.base &= - mem.align;
183 }
185 static unsigned setupseg = SETUP_SEGMENT;
186 static unsigned setupofs = 0;
188 void movesetup(void)
189 {
190 #asm
191 push si
192 mov es, _setupseg
193 mov si, #_buffer
194 xchg di, _setupofs
195 mov cx, #BUFFERSZ/2
196 rep
197 movsw
198 xchg _setupofs, di
199 pop si
200 #endasm
201 }
203 static unsigned getcs(void)
204 {
205 #asm
206 mov ax, cs
207 #endasm
208 }
210 static unsigned long kernel_version = 0;
211 unsigned long loadkernel(void)
212 {
213 unsigned setup, n = BUFFERSZ;
214 unsigned long syssize = 0;
216 do {
217 isoread(buffer, n);
218 if (setupofs == 0) {
219 if (* (unsigned short *) (buffer + BOOTFLAG) != 0xAA55)
220 die("The kernel is not bootable");
221 #asm
222 int 0x12
223 jc has640k
224 dec ax
225 and al, #0xC0
226 mov cl, #6
227 shl ax, cl
228 cmp ax, _setupseg
229 jnc has640k
230 mov _setupseg, ax
231 has640k:
232 #endasm
233 setup = (1 + buffer[SETUPSECTORS]) << 9;
234 if (setup == 512) setup = 5 << 9;
235 syssize = * (unsigned long *) (buffer + SYSSIZE) << 4;
236 if (!syssize) syssize = 0x7F000;
237 setup_version = * (unsigned short *) (buffer + VERSION);
238 #define HDRS 0x53726448
239 if (* (unsigned long *) (buffer + HEADER) != HDRS)
240 setup_version = 0;
241 #define ELKS 0x534B4C45
242 if (* (unsigned long *) (buffer + ELKSSIG) == ELKS)
243 iselks = 1;
244 if (setup_version < 0x204)
245 syssize &= 0x000FFFFFUL;
246 if (setup_version) {
247 #ifdef REALMODE_SWITCH
248 extern int far_realmode_switch();
249 #asm
250 jmp end_realmode_switch
251 _far_realmode_switch:
252 call REALMODE_SWITCH
253 cli
254 mov al, #0x80 // Disable NMI
255 out 0x70, al
256 retf
257 end_realmode_switch:
258 #endasm
259 * (unsigned short *) (buffer + RMSWOFS) =
260 far_realmode_switch;
261 * (unsigned short *) (buffer + RMSWSEG) =
262 getcs();
263 #endif
264 mem.base =
265 * (unsigned long *) (buffer + SYSTEMCODE);
266 * (unsigned short *) (buffer + HEAPPTR) =
267 0x9B00;
268 // buffer[LOADFLAGS] |= 0x80;
269 * (unsigned short *) (buffer + LOADERTYPE) |=
270 0x80FF;
271 }
272 if (!setup_version || !(buffer[LOADFLAGS] & 1)) {
273 #ifdef ZIMAGE_SUPPORT
274 zimage = getss() + 0x1000;
275 mem.base = zimage * 16L;
276 if (mem.base + syssize > setupseg*16L - 32) {
277 #ifdef FULL_ZIMAGE
278 zimage = 0x11;
279 mem.base = 0x110000L; // 1M + 64K HMA
280 #else
281 die("Out of memory");
282 #endif
283 }
284 #else
285 die("Not a bzImage format");
286 #endif
287 }
288 }
289 movesetup();
290 setup -= n;
291 n = (setup > BUFFERSZ) ? BUFFERSZ : setup;
292 } while (setup > 0);
294 #asm
295 push si
296 mov si, #0x200
297 cmp si, _setup_version
298 jae noversion
299 push ds
300 mov ds, _setupseg // setup > 2.00 => 386+
301 xor eax, eax
302 cdq // clear edx
303 add si, [si+14]
304 mov cx, #3
305 nextdigit:
306 shl al, #4
307 shl ax, #4
308 next:
309 lodsb
310 sub al, #0x30
311 cmp al, #9
312 jbe nextdigit
313 shl eax, #16
314 shld edx, eax, #8
315 loop next
316 pop ds
317 mov _kernel_version, edx
318 noversion:
319 pop si
320 #endasm
321 load(syssize);
322 return kernel_version;
323 }
325 void loadinitrd(void)
326 {
327 if (setup_version)
328 load(isofilesize);
329 }
331 void bootlinux(char *cmdline)
332 {
333 dosshutdown();
334 #asm
335 mov es, _setupseg
336 #endasm
337 if (cmdline) {
338 if (setup_version <= 0x201) {
339 #asm
340 mov di, #0x0020
341 mov ax, #0xA33F
342 stosw
343 mov ax, #CMDLINE_OFFSET
344 stosw
345 #endasm
346 }
347 else {
348 #asm
349 mov di, #0x0228
350 mov eax, #SETUP_SEGMENT*16+CMDLINE_OFFSET
351 stosd
352 #endasm
353 }
354 #asm
355 xchg ax, di
356 mov si, .bootlinux.cmdline[bp]
357 copy:
358 lodsb
359 stosb
360 or al,al
361 jne copy
362 #endasm
363 }
364 if (setup_version >= 0x200) {
365 #asm
366 mov eax, _initrd_addr
367 mov di, #0x218
368 stosd
369 mov eax, _initrd_size
370 stosd
371 #endasm
372 }
373 #asm
374 push es
375 pop ss
376 mov sp, #CMDLINE_OFFSET
377 #endasm
378 #ifdef ZIMAGE_SUPPORT
379 #asm
380 cld
381 mov ax, _mem
382 mov dx, _mem+2
383 mov bx, _zimage
384 mov bp, _iselks
385 mov si, #sysmove
386 mov di, #SETUP_END
387 mov cx, #endsysmove-sysmove
388 or bx, bx
389 jz notzimage
390 push cs
391 pop ds
392 push es
393 push di
394 rep
395 movsb
396 retf
397 sysmove:
398 #ifdef FULL_ZIMAGE
399 cmp dx, #0x0010
400 jb lowsys
401 // bx first 64k page, dx:ax last byte+1
402 xchg ax, cx // clear ax
403 jcxz aligned
404 inc dx
405 aligned:
406 mov si, di
407 mov cx, #0x18
408 rep
409 stosw
410 push es
411 pop ds
412 dec cx
413 mov [si+0x10], cx // limit = -1
414 mov [si+0x18], cx // limit = -1
415 mov cx, #0x9300+SYSTEM_SEGMENT/0x1000
416 mov bh, #0x93
417 mvdown:
418 mov [si+0x12+2], bx // srce
419 mov [si+0x1A+2], cx // dest
420 pusha // more than 1Mb => 286+
421 mov cx, #0x8000
422 mov ah, #0x87
423 int 0x15
424 popa
425 inc bx
426 inc cx
427 cmp dl, bl
428 ja mvdown
429 jmp notzimage
430 #endif
431 lowsys:
432 // bx first segment, dx:ax last byte+1 (paragraph aligned)
433 mov cl, #4
434 shr ax, cl
435 mov cl, #12
436 shl dx, cl
437 or ax, dx // last segment+1
438 mov dx, #SYSTEM_SEGMENT
439 sub ax, bx // ax = paragraph count
440 sub bx, dx
441 jnc sysmovelp
442 add dx, ax // top down
443 dec dx
444 sysmovelp: // move ax paragraphs from bx+dx:0 to dx:0
445 mov es, dx
446 mov cx, dx
447 add cx, bx
448 mov ds, cx
449 sbb cx, cx // cx = 0 : -1
450 cmc // C = 1 : 0
451 adc dx, cx
452 xor di, di
453 xor si, si
454 mov cx, #8
455 rep
456 movsw
457 dec ax
458 jne sysmovelp
459 notzimage:
460 or bp, bp
461 jz notelks
462 push ss
463 pop ds
464 mov cx, #0x100
465 mov es, cx
466 mov ch, #0x78 // do not overload SYSTEM_SEGMENT
467 xor si, si
468 xor di, di
469 push es
470 rep
471 movsw
472 pop ss
473 notelks:
474 #endasm
475 #endif
476 #asm
477 mov ax, ss
478 mov ds, ax
479 mov es, ax
480 add ax, #0x20
481 push ax
482 xor dx, dx
483 push dx
484 retf
485 endsysmove:
486 #endasm
487 }