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

syslinux/iso2exe: add 64bits support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sat Dec 27 17:56:57 2014 +0100 (2014-12-27)
parents 188b82599301
children 054f70cb9bec
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 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 if (setup == 512) {
264 #ifdef LINUX001_SUPPORT
265 if (WORD(buffer + 0x3F) == 0x3AE8) /* linux 0.01 */
266 goto linux001;
267 #endif
268 setup = 5 << 9;
269 }
270 #ifdef LINUX001_SUPPORT
271 n = BUFFERSZ;
272 isoread(buffer+512, BUFFERSZ-512);
273 #endif
274 #define HDRS 0x53726448
275 if (LONG(buffer + HEADER) == HDRS)
276 setup_version = WORD(buffer + VERSION);
277 #define ELKS 0x534B4C45
278 if (LONG(buffer + ELKSSIG) == ELKS)
279 iselks = 1;
280 if (setup_version < 0x204)
281 syssize &= 0x000FFFFFUL;
282 if (setup_version) {
283 #ifdef REALMODE_SWITCH
284 extern int far_realmode_switch();
285 #asm
286 jmp end_realmode_switch
287 _far_realmode_switch:
288 call REALMODE_SWITCH
289 cli
290 mov al, #0x80 // Disable NMI
291 out 0x70, al
292 retf
293 end_realmode_switch:
294 #endasm
295 WORD(buffer + RMSWOFS) = far_realmode_switch;
296 WORD(buffer + RMSWSEG) = getcs();
297 #endif
298 mem.base = LONG(buffer + SYSTEMCODE);
299 WORD(buffer + HEAPPTR) = 0x9B00;
300 // buffer[LOADFLAGS] |= 0x80;
301 WORD(buffer + LOADERTYPE) |= 0x80FF;
302 }
303 #ifdef LINUX001_SUPPORT
304 linux001:
305 #endif
306 if (!setup_version || !(buffer[LOADFLAGS] & 1)) {
307 zimage = getss() + 0x1000;
308 mem.base = zimage * 16L;
309 if (mem.base + syssize > setupseg*16L - 32) {
310 zimage = 0x9311;
311 mem.base = 0x110000L; // 1M + 64K HMA
312 }
313 }
314 }
315 movesetup();
316 setup -= n;
317 n = (setup > BUFFERSZ) ? BUFFERSZ : setup;
318 } while (setup > 0);
320 #asm
321 push si
322 mov si, #0x200
323 cmp si, _setup_version
324 jae noversion
325 mov es, _setupseg
326 seg es
327 add si, [si+14]
328 mov bx, #2
329 mov cl, #4
330 nextnumber:
331 xor ax, ax
332 nextdigit:
333 shl al, cl
334 shl ax, cl
335 seg es
336 lodsb
337 sub al, #0x30
338 cmp al, #9
339 jbe nextdigit
340 mov [bx+_kernel_version], ah
341 dec bx
342 jns nextnumber
343 noversion:
344 pop si
345 #endasm
346 load(syssize);
347 return kernel_version;
348 }
350 void loadinitrd(void)
351 {
352 if (setup_version)
353 load(isofilesize);
354 }
356 void bootlinux(char *cmdline)
357 {
358 dosshutdown();
359 #asm
360 cld
361 mov es, _setupseg
362 mov ax, _setup_version
363 cmp ax, #0x200
364 jb noinitrd
365 mov di, #0x218
366 mov si, #_initrd_addr
367 movsw
368 movsw
369 mov si, #_initrd_size
370 movsw
371 movsw
372 noinitrd:
373 mov si, [bp+4] // .bootlinux.cmdline[bp]
374 or si, si
375 jz nocmdline
376 cmp ax, #0x201
377 mov di, #0x0020
378 mov ax, #0xA33F
379 mov bx, #CMDLINE_OFFSET
380 push bx
381 jbe oldcmdline
382 mov di, #0x0228
383 mov ax, es
384 mov cl, #12
385 shr ax, cl
386 xchg ax, bx
387 oldcmdline:
388 stosw
389 xchg ax, bx
390 stosw
391 pop di
392 copy:
393 lodsb
394 stosb
395 or al,al
396 jne copy
397 nocmdline:
398 push es
399 pop ss
400 mov sp, #CMDLINE_OFFSET
401 mov ax, _mem
402 mov dx, _mem+2
403 mov bx, _zimage
404 mov bp, _iselks
405 mov si, #sysmove
406 mov di, #SETUP_END
407 mov cx, #endsysmove-sysmove
408 or bx, bx
409 jz notzimage
410 push cs
411 pop ds
412 push es
413 push di
414 rep
415 movsb
416 retf
417 sysmove:
418 cmp dx, #0x0010
419 jb lowsys
420 // bx first 64k page, dx:ax last byte+1
421 xchg ax, cx // clear ax
422 jcxz aligned
423 inc dx
424 aligned:
425 mov si, di
426 mov cx, #0x18
427 rep
428 stosw
429 push es
430 pop ds
431 dec cx
432 mov [si+0x10], cx // limit = -1
433 mov [si+0x18], cx // limit = -1
434 mov cx, #0x9300+SYSTEM_SEGMENT/0x1000
435 //mov bh, #0x93
436 mvdown:
437 mov [si+0x12+2], bx // srce
438 mov [si+0x1A+2], cx // dest
439 use16 286 // more than 1Mb => 286+
440 pusha
441 mov cx, #0x8000
442 mov ah, #0x87
443 int 0x15
444 popa
445 use16 86
446 inc bx
447 inc cx
448 cmp dl, bl
449 ja mvdown
450 jmp notzimage
451 lowsys:
452 // bx first segment, dx:ax last byte+1 (paragraph aligned)
453 mov cl, #4 // elks may run on a 8086
454 shr ax, cl
455 shl dx, cl
456 or ah, dl // last segment+1
457 mov dx, #SYSTEM_SEGMENT
458 sub ax, bx // ax = paragraph count
459 sub bx, dx
460 jnc sysmovelp
461 add dx, ax // top down
462 dec dx
463 sysmovelp: // move ax paragraphs from bx+dx:0 to dx:0
464 mov es, dx
465 mov si, dx
466 add si, bx
467 mov ds, si
468 sbb si, si // si = 0 : -1
469 cmc // C = 1 : 0
470 adc dx, si
471 mov cl, #8
472 xor di, di
473 xor si, si
474 rep
475 movsw
476 dec ax
477 jne sysmovelp
478 notzimage:
479 mov ax, ss
480 mov ds, ax
481 dec bp
482 jnz notelks
483 mov ah, #0x1
484 mov ss, ax
485 notelks:
486 push ss
487 pop es
488 xor di, di
489 xor si, si
490 #ifdef LINUX001_SUPPORT
491 mov cx, #0x0042
492 cmp word ptr [si+0x3F], #0x3AE8
493 je islinux001
494 #endif
495 mov cx, #0x7800 // do not overload SYSTEM_SEGMENT
496 rep
497 movsw
498 push es
499 pop ds
500 xor al, #0x20
501 islinux001:
502 push ax
503 push cx
504 retf
505 endsysmove:
506 #endasm
507 }