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 15 ! NOTE! These had better be the same as in bootsect.s! 16 #include <linux/config.h> 17 #define NORMAL_VGA 0xffff 18 19 INITSEG = DEF_INITSEG ! we move boot here - out of the way 20 SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). 21 SETUPSEG = DEF_SETUPSEG ! this is the current segment 22 23 .globl begtext, begdata, begbss, endtext, enddata, endbss 24 .text 25 begtext: 26 .data 27 begdata: 28 .bss 29 begbss: 30 .text 31 32 entry start 33 start: 34 35 ! ok, the read went well so we get current cursor position and save it for 36 ! posterity. 37 38 mov ax,#INITSEG ! this is done in bootsect already, but... 39 mov ds,ax 40 41 ! Get memory size (extended mem, kB) 42 43 mov ah,#0x88 44 int 0x15 45 mov [2],ax 46 47 ! set the keyboard repeat rate to the max 48 49 mov ax,#0x0305 50 mov bx,#0x0000 51 int 0x16 52 53 ! check for EGA/VGA and some config parameters 54 55 mov ah,#0x12 56 mov bl,#0x10 57 int 0x10 58 mov [8],ax 59 mov [10],bx 60 mov [12],cx 61 mov ax,#0x5019 62 cmp bl,#0x10 63 je novga 64 call chsvga 65 novga: mov [14],ax 66 mov ah,#0x03 ! read cursor pos 67 xor bh,bh 68 int 0x10 ! save it in known place, con_init fetches 69 mov [0],dx ! it from 0x90000. 70 71 ! Get video-card data: 72 73 mov ah,#0x0f 74 int 0x10 75 mov [4],bx ! bh = display page 76 mov [6],ax ! al = video mode, ah = window width 77 78 ! Get hd0 data 79 80 mov ax,#0x0000 81 mov ds,ax 82 lds si,[4*0x41] 83 mov ax,#INITSEG 84 mov es,ax 85 mov di,#0x0080 86 mov cx,#0x10 87 cld 88 rep 89 movsb 90 91 ! Get hd1 data 92 93 mov ax,#0x0000 94 mov ds,ax 95 lds si,[4*0x46] 96 mov ax,#INITSEG 97 mov es,ax 98 mov di,#0x0090 99 mov cx,#0x10 100 cld 101 rep 102 movsb 103 104 ! Check that there IS a hd1 :-) 105 106 mov ax,#0x01500 107 mov dl,#0x81 108 int 0x13 109 jc no_disk1 110 cmp ah,#3 111 je is_disk1 112 no_disk1: 113 mov ax,#INITSEG 114 mov es,ax 115 mov di,#0x0090 116 mov cx,#0x10 117 mov ax,#0x00 118 cld 119 rep 120 stosb 121 is_disk1: 122 123 ! now we want to move to protected mode ... 124 125 cli ! no interrupts allowed ! 126 127 ! first we move the system to it's rightful place 128 129 mov ax,#0x0000 130 cld ! 'direction'=0, movs moves forward 131 do_move: 132 mov es,ax ! destination segment 133 add ax,#0x1000 134 cmp ax,#0x9000 135 jz end_move 136 mov ds,ax ! source segment 137 sub di,di 138 sub si,si 139 mov cx,#0x8000 140 rep 141 movsw 142 jmp do_move 143 144 ! then we load the segment descriptors 145 146 end_move: 147 mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-) 148 mov ds,ax 149 lidt idt_48 ! load idt with 0,0 150 lgdt gdt_48 ! load gdt with whatever appropriate 151 152 ! that was painless, now we enable A20 153 154 call empty_8042 155 mov al,#0xD1 ! command write 156 out #0x64,al 157 call empty_8042 158 mov al,#0xDF ! A20 on 159 out #0x60,al 160 call empty_8042 161 162 ! well, that went ok, I hope. Now we have to reprogram the interrupts :-( 163 ! we put them right after the intel-reserved hardware interrupts, at 164 ! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really 165 ! messed this up with the original PC, and they haven't been able to 166 ! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, 167 ! which is used for the internal hardware interrupts as well. We just 168 ! have to reprogram the 8259's, and it isn't fun. 169 170 mov al,#0x11 ! initialization sequence 171 out #0x20,al ! send it to 8259A-1 172 .word 0x00eb,0x00eb ! jmp $+2, jmp $+2 173 out #0xA0,al ! and to 8259A-2 174 .word 0x00eb,0x00eb 175 mov al,#0x20 ! start of hardware int's (0x20) 176 out #0x21,al 177 .word 0x00eb,0x00eb 178 mov al,#0x28 ! start of hardware int's 2 (0x28) 179 out #0xA1,al 180 .word 0x00eb,0x00eb 181 mov al,#0x04 ! 8259-1 is master 182 out #0x21,al 183 .word 0x00eb,0x00eb 184 mov al,#0x02 ! 8259-2 is slave 185 out #0xA1,al 186 .word 0x00eb,0x00eb 187 mov al,#0x01 ! 8086 mode for both 188 out #0x21,al 189 .word 0x00eb,0x00eb 190 out #0xA1,al 191 .word 0x00eb,0x00eb 192 mov al,#0xFF ! mask off all interrupts for now 193 out #0xA1,al 194 .word 0x00eb,0x00eb 195 mov al,#0xFB ! mask all irq's but irq2 which 196 out #0x21,al ! is cascaded 197 198 ! well, that certainly wasn't fun :-(. Hopefully it works, and we don't 199 ! need no steenking BIOS anyway (except for the initial loading :-). 200 ! The BIOS-routine wants lots of unnecessary data, and it's less 201 ! "interesting" anyway. This is how REAL programmers do it. 202 ! 203 ! Well, now's the time to actually move into protected mode. To make 204 ! things as simple as possible, we do no register set-up or anything, 205 ! we let the gnu-compiled 32-bit programs do that. We just jump to 206 ! absolute address 0x00000, in 32-bit protected mode. 207 208 mov ax,#0x0001 ! protected mode (PE) bit 209 lmsw ax ! This is it! 210 jmpi 0,8 ! jmp offset 0 of segment 8 (cs) 211 212 ! This routine checks that the keyboard command queue is empty 213 ! No timeout is used - if this hangs there is something wrong with 214 ! the machine, and we probably couldn't proceed anyway. 215 empty_8042: 216 .word 0x00eb,0x00eb 217 in al,#0x64 ! 8042 status port 218 test al,#2 ! is input buffer full? 219 jnz empty_8042 ! yes - loop 220 ret 221 222 getkey: 223 in al,#0x60 ! Quick and dirty... 224 .word 0x00eb,0x00eb ! jmp $+2, jmp $+2 225 mov bl,al 226 in al,#0x61 227 .word 0x00eb,0x00eb 228 mov ah,al 229 or al,#0x80 230 out #0x61,al 231 .word 0x00eb,0x00eb 232 mov al,ah 233 out #0x61,al 234 .word 0x00eb,0x00eb 235 mov al,bl 236 ret 237 238 ! Routine trying to recognize type of SVGA-board present (if any) 239 ! and if it recognize one gives the choices of resolution it offers. 240 ! If one is found the resolution chosen is given by al,ah (rows,cols). 241 242 chsvga: cld 243 push ds 244 push cs 245 pop ds 246 mov ax,#0xc000 247 mov es,ax 248 lea si,msg1 249 call prtstr 250 #ifndef SVGA_MODE 251 flush: in al,#0x60 ! Flush the keyboard buffer 252 cmp al,#0x82 253 jb nokey 254 jmp flush 255 nokey: call getkey 256 cmp al,#0x82 257 jb nokey 258 cmp al,#0xe0 259 ja nokey 260 cmp al,#0x9c 261 je svga 262 #endif 263 #if !defined(SVGA_MODE) || SVGA_MODE == NORMAL_VGA 264 mov ax,#0x5019 265 pop ds 266 ret 267 #endif 268 svga: cld 269 lea si,idati ! Check ATI 'clues' 270 mov di,#0x31 271 mov cx,#0x09 272 repe 273 cmpsb 274 jne noati 275 lea si,dscati 276 lea di,moati 277 lea cx,selmod 278 jmp cx 279 noati: mov ax,#0x200f ! Check Ahead 'clues' 280 mov dx,#0x3ce 281 out dx,ax 282 inc dx 283 in al,dx 284 cmp al,#0x20 285 je isahed 286 cmp al,#0x21 287 jne noahed 288 isahed: lea si,dscahead 289 lea di,moahead 290 lea cx,selmod 291 jmp cx 292 noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues' 293 in al,dx 294 or al,#0x10 295 out dx,al 296 mov dx,#0x104 297 in al,dx 298 mov bl,al 299 mov dx,#0x3c3 300 in al,dx 301 and al,#0xef 302 out dx,al 303 cmp bl,[idcandt] 304 jne nocant 305 lea si,dsccandt 306 lea di,mocandt 307 lea cx,selmod 308 jmp cx 309 nocant: mov dx,#0x3d4 ! Check Cirrus 'clues' 310 mov al,#0x0c 311 out dx,al 312 inc dx 313 in al,dx 314 mov bl,al 315 xor al,al 316 out dx,al 317 dec dx 318 mov al,#0x1f 319 out dx,al 320 inc dx 321 in al,dx 322 mov bh,al 323 xor ah,ah 324 shl al,#4 325 mov cx,ax 326 mov al,bh 327 shr al,#4 328 add cx,ax 329 shl cx,#8 330 add cx,#6 331 mov ax,cx 332 mov dx,#0x3c4 333 out dx,ax 334 inc dx 335 in al,dx 336 and al,al 337 jnz nocirr 338 mov al,bh 339 out dx,al 340 in al,dx 341 cmp al,#0x01 342 jne nocirr 343 call rst3d4 344 lea si,dsccirrus 345 lea di,mocirrus 346 lea cx,selmod 347 jmp cx 348 rst3d4: mov dx,#0x3d4 349 mov al,bl 350 xor ah,ah 351 shl ax,#8 352 add ax,#0x0c 353 out dx,ax 354 ret 355 nocirr: call rst3d4 ! Check Everex 'clues' 356 mov ax,#0x7000 357 xor bx,bx 358 int 0x10 359 cmp al,#0x70 360 jne noevrx 361 shr dx,#4 362 cmp dx,#0x678 363 je istrid 364 cmp dx,#0x236 365 je istrid 366 lea si,dsceverex 367 lea di,moeverex 368 lea cx,selmod 369 jmp cx 370 istrid: lea cx,ev2tri 371 jmp cx 372 noevrx: lea si,idgenoa ! Check Genoa 'clues' 373 xor ax,ax 374 seg es 375 mov al,[0x37] 376 mov di,ax 377 mov cx,#0x04 378 dec si 379 dec di 380 l1: inc si 381 inc di 382 mov al,(si) 383 seg es 384 and al,(di) 385 cmp al,(si) 386 loope l1 387 cmp cx,#0x00 388 jne nogen 389 lea si,dscgenoa 390 lea di,mogenoa 391 lea cx,selmod 392 jmp cx 393 nogen: cld 394 lea si,idparadise ! Check Paradise 'clues' 395 mov di,#0x7d 396 mov cx,#0x04 397 repe 398 cmpsb 399 jne nopara 400 lea si,dscparadise 401 lea di,moparadise 402 lea cx,selmod 403 jmp cx 404 nopara: mov dx,#0x3c4 ! Check Trident 'clues' 405 mov al,#0x0e 406 out dx,al 407 inc dx 408 in al,dx 409 xchg ah,al 410 mov al,#0x00 411 out dx,al 412 in al,dx 413 xchg al,ah 414 mov bl,al ! Strange thing ... in the book this wasn't 415 and bl,#0x02 ! necessary but it worked on my card which 416 jz setb2 ! is a trident. Without it the screen goes 417 and al,#0xfd ! blurred ... 418 jmp clrb2 ! 419 setb2: or al,#0x02 ! 420 clrb2: out dx,al 421 and ah,#0x0f 422 cmp ah,#0x02 423 jne notrid 424 ev2tri: lea si,dsctrident 425 lea di,motrident 426 lea cx,selmod 427 jmp cx 428 notrid: mov dx,#0x3cd ! Check Tseng 'clues' 429 in al,dx ! Could things be this simple ! :-) 430 mov bl,al 431 mov al,#0x55 432 out dx,al 433 in al,dx 434 mov ah,al 435 mov al,bl 436 out dx,al 437 cmp ah,#0x55 438 jne notsen 439 lea si,dsctseng 440 lea di,motseng 441 lea cx,selmod 442 jmp cx 443 notsen: mov dx,#0x3cc ! Check Video7 'clues' 444 in al,dx 445 mov dx,#0x3b4 446 and al,#0x01 447 jz even7 448 mov dx,#0x3d4 449 even7: mov al,#0x0c 450 out dx,al 451 inc dx 452 in al,dx 453 mov bl,al 454 mov al,#0x55 455 out dx,al 456 in al,dx 457 dec dx 458 mov al,#0x1f 459 out dx,al 460 inc dx 461 in al,dx 462 mov bh,al 463 dec dx 464 mov al,#0x0c 465 out dx,al 466 inc dx 467 mov al,bl 468 out dx,al 469 mov al,#0x55 470 xor al,#0xea 471 cmp al,bh 472 jne novid7 473 lea si,dscvideo7 474 lea di,movideo7 475 selmod: push si 476 lea si,msg2 477 call prtstr 478 xor cx,cx 479 mov cl,(di) 480 pop si 481 push si 482 push cx 483 tbl: pop bx 484 push bx 485 mov al,bl 486 sub al,cl 487 call dprnt 488 call spcing 489 lodsw 490 xchg al,ah 491 call dprnt 492 xchg ah,al 493 push ax 494 mov al,#0x78 495 call prnt1 496 pop ax 497 call dprnt 498 call docr 499 loop tbl 500 pop cx 501 call docr 502 lea si,msg3 503 call prtstr 504 pop si 505 add cl,#0x80 506 #if defined(SVGA_MODE) && SVGA_MODE != NORMAL_VGA 507 mov al,#SVGA_MODE ! Preset SVGA mode 508 #else 509 nonum: call getkey 510 cmp al,#0x82 511 jb nonum 512 cmp al,#0x8b 513 je zero 514 cmp al,cl 515 ja nonum 516 jmp nozero 517 zero: sub al,#0x0a 518 nozero: sub al,#0x80 519 dec al 520 #endif 521 xor ah,ah 522 add di,ax 523 inc di 524 push ax 525 mov al,(di) 526 int 0x10 527 pop ax 528 shl ax,#1 529 add si,ax 530 lodsw 531 pop ds 532 ret 533 novid7: 534 mov ax,#0x1112 535 mov bl,#0 536 int 0x10 ! use 8x8 font set (50 lines on VGA) 537 538 mov ax,#0x1200 539 mov bl,#0x20 540 int 0x10 ! use alternate print screen 541 542 mov ax,#0x1201 543 mov bl,#0x34 544 int 0x10 ! turn off cursor emulation 545 546 mov ah,#0x01 547 mov cx,#0x0607 548 int 0x10 ! turn on cursor (scan lines 6 to 7) 549 550 pop ds 551 mov ax,#0x5032 ! return 80x50 552 ret 553 554 ! Routine that 'tabs' to next col. 555 556 spcing: mov al,#0x2e 557 call prnt1 558 mov al,#0x20 559 call prnt1 560 mov al,#0x20 561 call prnt1 562 mov al,#0x20 563 call prnt1 564 mov al,#0x20 565 call prnt1 566 ret 567 568 ! Routine to print asciiz-string at DS:SI 569 570 prtstr: lodsb 571 and al,al 572 jz fin 573 call prnt1 574 jmp prtstr 575 fin: ret 576 577 ! Routine to print a decimal value on screen, the value to be 578 ! printed is put in al (i.e 0-255). 579 580 dprnt: push ax 581 push cx 582 mov ah,#0x00 583 mov cl,#0x0a 584 idiv cl 585 cmp al,#0x09 586 jbe lt100 587 call dprnt 588 jmp skip10 589 lt100: add al,#0x30 590 call prnt1 591 skip10: mov al,ah 592 add al,#0x30 593 call prnt1 594 pop cx 595 pop ax 596 ret 597 598 ! Part of above routine, this one just prints ascii al 599 600 prnt1: push ax 601 push cx 602 mov bh,#0x00 603 mov cx,#0x01 604 mov ah,#0x0e 605 int 0x10 606 pop cx 607 pop ax 608 ret 609 610 ! Prints <CR> + <LF> 611 612 docr: push ax 613 push cx 614 mov bh,#0x00 615 mov ah,#0x0e 616 mov al,#0x0a 617 mov cx,#0x01 618 int 0x10 619 mov al,#0x0d 620 int 0x10 621 pop cx 622 pop ax 623 ret 624 625 gdt: 626 .word 0,0,0,0 ! dummy 627 628 .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) 629 .word 0x0000 ! base address=0 630 .word 0x9A00 ! code read/exec 631 .word 0x00C0 ! granularity=4096, 386 632 633 .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) 634 .word 0x0000 ! base address=0 635 .word 0x9200 ! data read/write 636 .word 0x00C0 ! granularity=4096, 386 637 638 idt_48: 639 .word 0 ! idt limit=0 640 .word 0,0 ! idt base=0L 641 642 gdt_48: 643 .word 0x800 ! gdt limit=2048, 256 GDT entries 644 .word 512+gdt,0x9 ! gdt base = 0X9xxxx 645 646 msg1: .ascii "Press <RETURN> to see SVGA-modes available or any other key to continue." 647 db 0x0d, 0x0a, 0x0a, 0x00 648 msg2: .ascii "Mode: COLSxROWS:" 649 db 0x0d, 0x0a, 0x0a, 0x00 650 msg3: .ascii "Choose mode by pressing the corresponding number." 651 db 0x0d, 0x0a, 0x00 652 653 idati: .ascii "761295520" 654 idcandt: .byte 0xa5 655 idgenoa: .byte 0x77, 0x00, 0x66, 0x99 656 idparadise: .ascii "VGA=" 657 658 ! Manufacturer: Numofmodes: Mode: 659 660 moati: .byte 0x02, 0x23, 0x33 661 moahead: .byte 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34 662 mocandt: .byte 0x02, 0x60, 0x61 663 mocirrus: .byte 0x04, 0x1f, 0x20, 0x22, 0x31 664 moeverex: .byte 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40 665 mogenoa: .byte 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78 666 moparadise: .byte 0x02, 0x55, 0x54 667 motrident: .byte 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a 668 motseng: .byte 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22 669 movideo7: .byte 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45 670 671 ! msb = Cols lsb = Rows: 672 673 dscati: .word 0x8419, 0x842c 674 dscahead: .word 0x842c, 0x8419, 0x841c, 0xa032, 0x5042 675 dsccandt: .word 0x8419, 0x8432 676 dsccirrus: .word 0x8419, 0x842c, 0x841e, 0x6425 677 dsceverex: .word 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e 678 dscgenoa: .word 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b 679 dscparadise: .word 0x8419, 0x842b 680 dsctrident: .word 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c 681 dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c 682 dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c 683 684 .text 685 endtext: 686 .data 687 enddata: 688 .bss 689 endbss: