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