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