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

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