1 ! 2 ! setup.S Copyright (C) 1991, 1992 Linus Torvalds 3 ! 4 ! setup.s is responsible for getting the system data from the BIOS, 5 ! and putting them into the appropriate places in system memory. 6 ! both setup.s and system has been loaded by the bootblock. 7 ! 8 ! This code asks the bios for memory/disk/other parameters, and 9 ! puts them in a "safe" place: 0x90000-0x901FF, ie where the 10 ! boot-block used to be. It is then up to the protected mode 11 ! system to read them from there before the area is overwritten 12 ! for buffer-blocks. 13 ! 14 ! Move PS/2 aux init code to psaux.c 15 ! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 16 ! 17 ! some changes and additional features by Christoph Niemann, 18 ! March 1993/June 1994 (Christoph.Niemann@linux.org) 19 ! 20 ! add APM BIOS checking by Stephen Rothwell, May 1994 21 ! (Stephen.Rothwell@pd.necisa.oz.au) 22 ! 23 ! High load stuff, initrd support and position independency 24 ! by Hans Lermen & Werner Almesberger, February 1996 25 ! <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch> 26 ! 27 ! Video handling moved to video.S by Martin Mares, March 1996 28 ! <mj@k332.feld.cvut.cz> 29 30 ! NOTE! These had better be the same as in bootsect.s! 31 #define __ASSEMBLY__ 32 #include <linux/config.h> 33 #include <asm/segment.h> 34 #include <linux/version.h> 35 #include <linux/compile.h> 36 37 ! Signature words to ensure LILO loaded us right 38 #define SIG1 0xAA55 39 #define SIG2 0x5A5A 40 41 INITSEG = DEF_INITSEG ! 0x9000, we move boot here - out of the way 42 SYSSEG = DEF_SYSSEG ! 0x1000, system loaded at 0x10000 (65536). 43 SETUPSEG = DEF_SETUPSEG ! 0x9020, this is the current segment 44 ! ... and the former contents of CS 45 DELTA_INITSEG = SETUPSEG - INITSEG ! 0x0020 46 47 .globl begtext, begdata, begbss, endtext, enddata, endbss 48 .text 49 begtext: 50 .data 51 begdata: 52 .bss 53 begbss: 54 .text 55 56 entry start 57 start: 58 jmp start_of_setup 59 ! ------------------------ start of header -------------------------------- 60 ! 61 ! SETUP-header, must start at CS:2 (old 0x9020:2) 62 ! 63 .ascii "HdrS" ! Signature for SETUP-header 64 .word 0x0201 ! Version number of header format 65 ! (must be >= 0x0105 66 ! else old loadlin-1.5 will fail) 67 realmode_swtch: .word 0,0 ! default_switch,SETUPSEG 68 start_sys_seg: .word SYSSEG 69 .word kernel_version ! pointing to kernel version string 70 ! note: above part of header is compatible with loadlin-1.5 (header v1.5), 71 ! must not change it 72 73 type_of_loader: .byte 0 ! = 0, old one (LILO, Loadlin, 74 ! Bootlin, SYSLX, bootsect...) 75 ! else it is set by the loader: 76 ! 0xTV: T=0 for LILO 77 ! T=1 for Loadlin 78 ! T=2 for bootsect-loader 79 ! T=3 for SYSLX 80 ! T=4 for ETHERBOOT 81 ! V = version 82 loadflags: .byte 0 ! unused bits =0 (reserved for future development) 83 LOADED_HIGH = 1 ! bit within loadflags, 84 ! if set, then the kernel is loaded high 85 CAN_USE_HEAP = 0x80 ! if set, the loader also has set heap_end_ptr 86 ! to tell how much space behind setup.S 87 | can be used for heap purposes. 88 ! Only the loader knows what is free! 89 setup_move_size: .word 0x8000 ! size to move, when we (setup) are not 90 ! loaded at 0x90000. We will move ourselves 91 ! to 0x90000 then just before jumping into 92 ! the kernel. However, only the loader 93 ! know how much of data behind us also needs 94 ! to be loaded. 95 code32_start: .long 0x1000 ! here loaders can put a different 96 ! start address for 32-bit code. 97 ! 0x1000 = default for zImage 98 ! 0x100000 = default for big kernel 99 ramdisk_image: .long 0 ! address of loaded ramdisk image 100 ! Here the loader (or kernel generator) puts 101 ! the 32-bit address were it loaded the image. 102 ! This only will be interpreted by the kernel. 103 ramdisk_size: .long 0 ! its size in bytes 104 bootsect_kludge: 105 .word bootsect_helper,SETUPSEG 106 heap_end_ptr: .word modelist+1024 ! space from here (exclusive) down to 107 ! end of setup code can be used by setup 108 ! for local heap purposes. 109 ! ------------------------ end of header ---------------------------------- 110 111 start_of_setup: 112 ! Bootlin depends on this being done early 113 mov ax,#0x01500 114 mov dl,#0x81 115 int 0x13 116 117 ! set DS=CS, we know that SETUPSEG == CS at this point 118 mov ax,cs ! aka #SETUPSEG 119 mov ds,ax 120 121 ! Check signature at end of setup 122 cmp setup_sig1,#SIG1 123 jne bad_sig 124 cmp setup_sig2,#SIG2 125 jne bad_sig 126 jmp good_sig1 127 128 ! Routine to print asciiz-string at DS:SI 129 130 prtstr: lodsb 131 and al,al 132 jz fin 133 call prtchr 134 jmp prtstr 135 fin: ret 136 137 ! Space printing 138 139 prtsp2: call prtspc ! Print double space 140 prtspc: mov al,#0x20 ! Print single space (fall-thru!) 141 142 ! Part of above routine, this one just prints ascii al 143 144 prtchr: push ax 145 push cx 146 xor bh,bh 147 mov cx,#0x01 148 mov ah,#0x0e 149 int 0x10 150 pop cx 151 pop ax 152 ret 153 154 beep: mov al,#0x07 155 jmp prtchr 156 157 no_sig_mess: .ascii "No setup signature found ..." 158 db 0x00 159 160 good_sig1: 161 jmp good_sig 162 163 ! We now have to find the rest of the setup code/data 164 bad_sig: 165 mov ax,cs ! aka #SETUPSEG 166 sub ax,#DELTA_INITSEG ! aka #INITSEG 167 mov ds,ax 168 xor bh,bh 169 mov bl,[497] ! get setup sects from boot sector 170 sub bx,#4 ! LILO loads 4 sectors of setup 171 shl bx,#8 ! convert to words 172 mov cx,bx 173 shr bx,#3 ! convert to segment 174 add bx,#SYSSEG 175 seg cs 176 mov start_sys_seg,bx 177 178 ! Move rest of setup code/data to here 179 mov di,#2048 ! four sectors loaded by LILO 180 sub si,si 181 mov ax,cs ! aka #SETUPSEG 182 mov es,ax 183 mov ax,#SYSSEG 184 mov ds,ax 185 rep 186 movsw 187 188 mov ax,cs ! aka #SETUPSEG 189 mov ds,ax 190 cmp setup_sig1,#SIG1 191 jne no_sig 192 cmp setup_sig2,#SIG2 193 jne no_sig 194 jmp good_sig 195 196 no_sig: 197 lea si,no_sig_mess 198 call prtstr 199 no_sig_loop: 200 jmp no_sig_loop 201 202 good_sig: 203 mov ax,cs ! aka #SETUPSEG 204 sub ax,#DELTA_INITSEG ! aka #INITSEG 205 mov ds,ax 206 207 ! check if an old loader tries to load a big-kernel 208 seg cs 209 test byte ptr loadflags,#LOADED_HIGH ! have we a big kernel ? 210 jz loader_ok ! NO, no danger even for old loaders 211 ! YES, we have a big-kernel 212 seg cs 213 cmp byte ptr type_of_loader,#0 ! have we one of the new loaders ? 214 jnz loader_ok ! YES, ok 215 ! NO, we have an old loader, must give up 216 push cs 217 pop ds 218 lea si,loader_panic_mess 219 call prtstr 220 jmp no_sig_loop 221 loader_panic_mess: 222 .ascii "Wrong loader, giving up..." 223 db 0 224 225 loader_ok: 226 ! Get memory size (extended mem, kB) 227 228 mov ah,#0x88 229 int 0x15 230 mov [2],ax 231 232 ! Set the keyboard repeat rate to the max 233 234 mov ax,#0x0305 235 xor bx,bx ! clear bx 236 int 0x16 237 238 ! Check for video adapter and its parameters and allow the 239 ! user to browse video modes. 240 241 call video ! NOTE: we need DS pointing to bootsector 242 243 ! Get hd0 data 244 245 xor ax,ax ! clear ax 246 mov ds,ax 247 lds si,[4*0x41] 248 mov ax,cs ! aka #SETUPSEG 249 sub ax,#DELTA_INITSEG ! aka #INITSEG 250 push ax 251 mov es,ax 252 mov di,#0x0080 253 mov cx,#0x10 254 push cx 255 cld 256 rep 257 movsb 258 259 ! Get hd1 data 260 261 xor ax,ax ! clear ax 262 mov ds,ax 263 lds si,[4*0x46] 264 pop cx 265 pop es 266 mov di,#0x0090 267 rep 268 movsb 269 270 ! Check that there IS a hd1 :-) 271 272 mov ax,#0x01500 273 mov dl,#0x81 274 int 0x13 275 jc no_disk1 276 cmp ah,#3 277 je is_disk1 278 no_disk1: 279 mov ax,cs ! aka #SETUPSEG 280 sub ax,#DELTA_INITSEG ! aka #INITSEG 281 mov es,ax 282 mov di,#0x0090 283 mov cx,#0x10 284 xor ax,ax ! clear ax 285 cld 286 rep 287 stosb 288 is_disk1: 289 290 ! Check for PS/2 pointing device 291 292 mov ax,cs ! aka #SETUPSEG 293 sub ax,#DELTA_INITSEG ! aka #INITSEG 294 mov ds,ax 295 mov [0x1ff],#0 ! default is no pointing device 296 int 0x11 ! int 0x11: equipment determination 297 test al,#0x04 ! check if pointing device installed 298 jz no_psmouse 299 mov [0x1ff],#0xaa ! device present 300 no_psmouse: 301 302 #ifdef CONFIG_APM 303 ! check for APM BIOS 304 ! NOTE: DS is pointing to the bootsector 305 ! 306 mov [64],#0 ! version == 0 means no APM BIOS 307 308 mov ax,#0x05300 ! APM BIOS installation check 309 xor bx,bx 310 int 0x15 311 jc done_apm_bios ! error -> no APM BIOS 312 313 cmp bx,#0x0504d ! check for "PM" signature 314 jne done_apm_bios ! no signature -> no APM BIOS 315 316 mov [64],ax ! record the APM BIOS version 317 mov [76],cx ! and flags 318 and cx,#0x02 ! Is 32 bit supported? 319 je done_apm_bios ! no ... 320 321 mov ax,#0x05304 ! Disconnect first just in case 322 xor bx,bx 323 int 0x15 ! ignore return code 324 325 mov ax,#0x05303 ! 32 bit connect 326 xor bx,bx 327 int 0x15 328 jc no_32_apm_bios ! error 329 330 mov [66],ax ! BIOS code segment 331 mov [68],ebx ! BIOS entry point offset 332 mov [72],cx ! BIOS 16 bit code segment 333 mov [74],dx ! BIOS data segment 334 mov [78],si ! BIOS code segment length 335 mov [80],di ! BIOS data segment length 336 jmp done_apm_bios 337 338 no_32_apm_bios: 339 and [76], #0xfffd ! remove 32 bit support bit 340 341 done_apm_bios: 342 #endif 343 344 ! Now we want to move to protected mode ... 345 346 seg cs 347 cmp realmode_swtch,#0 348 jz rmodeswtch_normal 349 seg cs 350 callf far * realmode_swtch 351 jmp rmodeswtch_end 352 rmodeswtch_normal: 353 push cs 354 call default_switch 355 rmodeswtch_end: 356 357 ! we get the code32 start address and modify the below 'jmpi' 358 ! (loader may have changed it) 359 seg cs 360 mov eax,code32_start 361 seg cs 362 mov code32,eax 363 364 ! Now we move the system to its rightful place 365 ! ...but we check, if we have a big-kernel. 366 ! in this case we *must* not move it ... 367 seg cs 368 test byte ptr loadflags,#LOADED_HIGH 369 jz do_move0 ! we have a normal low loaded zImage 370 ! we have a high loaded big kernel 371 jmp end_move ! ... and we skip moving 372 373 do_move0: 374 mov ax,#0x100 ! start of destination segment 375 mov bp,cs ! aka #SETUPSEG 376 sub bp,#DELTA_INITSEG ! aka #INITSEG 377 seg cs 378 mov bx,start_sys_seg ! start of source segment 379 cld ! 'direction'=0, movs moves forward 380 do_move: 381 mov es,ax ! destination segment 382 inc ah ! instead of add ax,#0x100 383 mov ds,bx ! source segment 384 add bx,#0x100 385 sub di,di 386 sub si,si 387 mov cx,#0x800 388 rep 389 movsw 390 cmp bx,bp ! we assume start_sys_seg > 0x200, 391 ! so we will perhaps read one page more then 392 ! needed, but never overwrite INITSEG because 393 ! destination is minimum one page below source 394 jb do_move 395 396 ! then we load the segment descriptors 397 398 end_move: 399 mov ax,cs ! aka #SETUPSEG ! right, forgot this at first. didn't work :-) 400 mov ds,ax 401 402 ! If we have our code not at 0x90000, we need to move it there now. 403 ! We also then need to move the params behind it (commandline) 404 ! Because we would overwrite the code on the current IP, we move 405 ! it in two steps, jumping high after the first one. 406 mov ax,cs 407 cmp ax,#SETUPSEG 408 je end_move_self 409 cli ! make sure we really have interrupts disabled ! 410 ! because after this the stack should not be used 411 sub ax,#DELTA_INITSEG ! aka #INITSEG 412 mov dx,ss 413 cmp dx,ax 414 jb move_self_1 415 add dx,#INITSEG 416 sub dx,ax ! this will be SS after the move 417 move_self_1: 418 mov ds,ax 419 mov ax,#INITSEG ! real INITSEG 420 mov es,ax 421 seg cs 422 mov cx,setup_move_size 423 std ! we have to move up, so we use direction down 424 ! because the areas may overlap 425 mov di,cx 426 dec di 427 mov si,di 428 sub cx,#move_self_here+0x200 429 rep 430 movsb 431 jmpi move_self_here,SETUPSEG ! jump to our final place 432 move_self_here: 433 mov cx,#move_self_here+0x200 434 rep 435 movsb 436 mov ax,#SETUPSEG 437 mov ds,ax 438 mov ss,dx 439 ! now we are at the right place 440 end_move_self: 441 442 lidt idt_48 ! load idt with 0,0 443 lgdt gdt_48 ! load gdt with whatever appropriate 444 445 ! that was painless, now we enable A20 446 447 call empty_8042 448 mov al,#0xD1 ! command write 449 out #0x64,al 450 call empty_8042 451 mov al,#0xDF ! A20 on 452 out #0x60,al 453 call empty_8042 454 455 ! make sure any possible coprocessor is properly reset.. 456 457 xor ax,ax 458 out #0xf0,al 459 call delay 460 out #0xf1,al 461 call delay 462 463 ! well, that went ok, I hope. Now we have to reprogram the interrupts :-( 464 ! we put them right after the intel-reserved hardware interrupts, at 465 ! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really 466 ! messed this up with the original PC, and they haven't been able to 467 ! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, 468 ! which is used for the internal hardware interrupts as well. We just 469 ! have to reprogram the 8259's, and it isn't fun. 470 471 mov al,#0x11 ! initialization sequence 472 out #0x20,al ! send it to 8259A-1 473 call delay 474 out #0xA0,al ! and to 8259A-2 475 call delay 476 mov al,#0x20 ! start of hardware int's (0x20) 477 out #0x21,al 478 call delay 479 mov al,#0x28 ! start of hardware int's 2 (0x28) 480 out #0xA1,al 481 call delay 482 mov al,#0x04 ! 8259-1 is master 483 out #0x21,al 484 call delay 485 mov al,#0x02 ! 8259-2 is slave 486 out #0xA1,al 487 call delay 488 mov al,#0x01 ! 8086 mode for both 489 out #0x21,al 490 call delay 491 out #0xA1,al 492 call delay 493 mov al,#0xFF ! mask off all interrupts for now 494 out #0xA1,al 495 call delay 496 mov al,#0xFB ! mask all irq's but irq2 which 497 out #0x21,al ! is cascaded 498 499 ! Well, that certainly wasn't fun :-(. Hopefully it works, and we don't 500 ! need no steenking BIOS anyway (except for the initial loading :-). 501 ! The BIOS-routine wants lots of unnecessary data, and it's less 502 ! "interesting" anyway. This is how REAL programmers do it. 503 ! 504 ! Well, now's the time to actually move into protected mode. To make 505 ! things as simple as possible, we do no register set-up or anything, 506 ! we let the gnu-compiled 32-bit programs do that. We just jump to 507 ! absolute address 0x1000 (or the loader supplied one), 508 ! in 32-bit protected mode. 509 ! 510 ! Note that the short jump isn't strictly needed, although there are 511 ! reasons why it might be a good idea. It won't hurt in any case. 512 ! 513 mov ax,#1 ! protected mode (PE) bit 514 lmsw ax ! This is it! 515 jmp flush_instr 516 flush_instr: 517 xor bx,bx ! Flag to indicate a boot 518 519 ! NOTE: For high loaded big kernels we need a 520 ! jmpi 0x100000,KERNEL_CS 521 ! 522 ! but we yet haven't reloaded the CS register, so the default size 523 ! of the target offset still is 16 bit. 524 ! However, using an operant prefix (0x66), the CPU will properly 525 ! take our 48 bit far pointer. (INTeL 80386 Programmer's Reference 526 ! Manual, Mixing 16-bit and 32-bit code, page 16-6) 527 db 0x66,0xea ! prefix + jmpi-opcode 528 code32: dd 0x1000 ! will be set to 0x100000 for big kernels 529 dw KERNEL_CS 530 531 532 kernel_version: .ascii UTS_RELEASE 533 .ascii " (" 534 .ascii LINUX_COMPILE_BY 535 .ascii "@" 536 .ascii LINUX_COMPILE_HOST 537 .ascii ") " 538 .ascii UTS_VERSION 539 db 0 540 541 ! This is the default real mode switch routine. 542 ! to be called just before protected mode transition 543 544 default_switch: 545 cli ! no interrupts allowed ! 546 mov al,#0x80 ! disable NMI for the bootup sequence 547 out #0x70,al 548 retf 549 550 ! This routine only gets called, if we get loaded by the simple 551 ! bootsect loader _and_ have a bzImage to load. 552 ! Because there is no place left in the 512 bytes of the boot sector, 553 ! we must emigrate to code space here. 554 ! 555 bootsect_helper: 556 seg cs 557 cmp word ptr bootsect_es,#0 558 jnz bootsect_second 559 seg cs 560 mov byte ptr type_of_loader,#0x20 561 mov ax,es 562 shr ax,#4 563 seg cs 564 mov byte ptr bootsect_src_base+2,ah 565 mov ax,es 566 seg cs 567 mov bootsect_es,ax 568 sub ax,#SYSSEG 569 retf ! nothing else to do for now 570 bootsect_second: 571 push cx 572 push si 573 push bx 574 test bx,bx ! 64K full ? 575 jne bootsect_ex 576 mov cx,#0x8000 ! full 64K move, INT15 moves words 577 push cs 578 pop es 579 mov si,#bootsect_gdt 580 mov ax,#0x8700 581 int 0x15 582 jc bootsect_panic ! this, if INT15 fails 583 seg cs 584 mov es,bootsect_es ! we reset es to always point to 0x10000 585 seg cs 586 inc byte ptr bootsect_dst_base+2 587 bootsect_ex: 588 seg cs 589 mov ah, byte ptr bootsect_dst_base+2 590 shl ah,4 ! we now have the number of moved frames in ax 591 xor al,al 592 pop bx 593 pop si 594 pop cx 595 retf 596 597 bootsect_gdt: 598 .word 0,0,0,0 599 .word 0,0,0,0 600 bootsect_src: 601 .word 0xffff 602 bootsect_src_base: 603 .byte 0,0,1 ! base = 0x010000 604 .byte 0x93 ! typbyte 605 .word 0 ! limit16,base24 =0 606 bootsect_dst: 607 .word 0xffff 608 bootsect_dst_base: 609 .byte 0,0,0x10 ! base = 0x100000 610 .byte 0x93 ! typbyte 611 .word 0 ! limit16,base24 =0 612 .word 0,0,0,0 ! BIOS CS 613 .word 0,0,0,0 ! BIOS DS 614 bootsect_es: 615 .word 0 616 617 bootsect_panic: 618 push cs 619 pop ds 620 cld 621 lea si,bootsect_panic_mess 622 call prtstr 623 bootsect_panic_loop: 624 jmp bootsect_panic_loop 625 bootsect_panic_mess: 626 .ascii "INT15 refuses to access high mem, giving up..." 627 db 0 628 629 ! This routine checks that the keyboard command queue is empty 630 ! (after emptying the output buffers) 631 ! 632 ! No timeout is used - if this hangs there is something wrong with 633 ! the machine, and we probably couldn't proceed anyway. 634 empty_8042: 635 call delay 636 in al,#0x64 ! 8042 status port 637 test al,#1 ! output buffer? 638 jz no_output 639 call delay 640 in al,#0x60 ! read it 641 jmp empty_8042 642 no_output: 643 test al,#2 ! is input buffer full? 644 jnz empty_8042 ! yes - loop 645 ret 646 647 ! 648 ! Read the cmos clock. Return the seconds in al 649 ! 650 gettime: 651 push cx 652 mov ah,#0x02 653 int 0x1a 654 mov al,dh ! dh contains the seconds 655 and al,#0x0f 656 mov ah,dh 657 mov cl,#0x04 658 shr ah,cl 659 aad 660 pop cx 661 ret 662 663 ! 664 ! Delay is needed after doing I/O 665 ! 666 delay: 667 .word 0x00eb ! jmp $+2 668 ret 669 670 ! 671 ! Descriptor tables 672 ! 673 674 gdt: 675 .word 0,0,0,0 ! dummy 676 677 .word 0,0,0,0 ! unused 678 679 .word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb) 680 .word 0x0000 ! base address=0 681 .word 0x9A00 ! code read/exec 682 .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit) 683 684 .word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb) 685 .word 0x0000 ! base address=0 686 .word 0x9200 ! data read/write 687 .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit) 688 689 idt_48: 690 .word 0 ! idt limit=0 691 .word 0,0 ! idt base=0L 692 693 gdt_48: 694 .word 0x800 ! gdt limit=2048, 256 GDT entries 695 .word 512+gdt,0x9 ! gdt base = 0X9xxxx 696 697 ! 698 ! Include video setup & detection code 699 ! 700 701 #include "video.S" 702 703 ! 704 ! Setup signature -- must be last 705 ! 706 707 setup_sig1: .word SIG1 708 setup_sig2: .word SIG2 709 710 ! 711 ! After this point, there is some free space which is used by the video mode 712 ! handling code to store the temporary mode table (not used by the kernel). 713 ! 714 715 modelist: 716 717 .text 718 endtext: 719 .data 720 enddata: 721 .bss 722 endbss: