wok view syslinux/stuff/iso2exe/bootlinux.c @ rev 17489

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