1 ! 2 ! setup.S Copyright (C) 1991, 1992 Linus Torvalds 3 ! 4 ! This code performs all initialization procedures that should be done 5 ! before entering the protected mode. It's responsible for getting of all 6 ! system data offered by BIOS and for detection / selection of video 7 ! mode. All information is put in a "safe" place: 0x90000-0x901FF, i. e. 8 ! where the boot-block used to be. It is then up to the protected mode 9 ! system to read them from there before the area is overwritten 10 ! for buffer-blocks. 11 ! 12 ! Move PS/2 aux init code to psaux.c 13 ! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 14 ! 15 ! Some changes and additional features by Christoph Niemann, 16 ! March 1993/June 1994 (Christoph.Niemann@linux.org) 17 ! 18 ! Completely new video-mode handling code, VESA mode detection, support 19 ! for new Cirrus Logic cards and some additional changes 20 ! by Martin Mares <mj@k332.feld.cvut.cz>, October 1995. 21 ! 22 23 ! NOTE! These had better be the same as in bootsect.S! 24 #define __ASSEMBLY__ 25 #include <linux/config.h> 26 #include <asm/segment.h> 27 28 ! Uncomment this if you want the BIOS mode numbers to be listed 29 !#define SHOW_BIOS_MODES 30 31 ! Signature words to ensure LILO loaded us right 32 #define SIG1 0xAA55 33 #define SIG2 0x5A5A 34 35 INITSEG = DEF_INITSEG ! we move boot here - out of the way 36 SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). 37 SETUPSEG = DEF_SETUPSEG ! this is the current segment 38 39 .globl begtext, begdata, begbss, endtext, enddata, endbss 40 .text 41 begtext: 42 .data 43 begdata: 44 .bss 45 begbss: 46 .text 47 48 entry start 49 start: 50 51 ! Bootlin depends on this being done early 52 mov ax,#0x01500 53 mov dl,#0x81 54 int 0x13 55 56 ! Check signature at end of setup 57 mov ax,#SETUPSEG 58 mov ds,ax 59 cmp setup_sig1,#SIG1 60 jne bad_sig 61 cmp setup_sig2,#SIG2 62 jne bad_sig 63 jmp good_sig1 64 65 ! Routine to print asciiz-string at DS:SI 66 67 prtstr: lodsb 68 and al,al 69 jz fin 70 call prnt1 71 jmp prtstr 72 fin: ret 73 74 ! Part of above routine, this one just prints ascii al 75 76 prnt1: push ax 77 push bx 78 push cx 79 xor bh,bh 80 mov cx,#0x01 81 mov ah,#0x0e 82 int 0x10 83 pop cx 84 pop bx 85 pop ax 86 ret 87 88 beep: mov al,#0x07 89 jmp prnt1 90 91 no_sig_mess: .ascii "No setup signature found ..." 92 db 0x00 93 start_sys_seg: .word SYSSEG 94 95 good_sig1: 96 jmp good_sig 97 98 ! We now have to find the rest of the setup code/data 99 bad_sig: 100 mov ax,#INITSEG 101 mov ds,ax 102 xor bh,bh 103 mov bl,[497] ! get setup sects from boot sector 104 sub bx,#4 ! LILO loads 4 sectors of setup 105 shl bx,#8 ! convert to words 106 mov cx,bx 107 shr bx,#3 ! convert to segment 108 add bx,#SYSSEG 109 seg cs 110 mov start_sys_seg,bx 111 112 ! Move rest of setup code/data to here 113 mov di,#2048 ! four sectors loaded by LILO 114 sub si,si 115 mov ax,#SETUPSEG 116 mov es,ax 117 mov ax,#SYSSEG 118 mov ds,ax 119 rep 120 movsw 121 122 mov ax,#SETUPSEG 123 mov ds,ax 124 cmp setup_sig1,#SIG1 125 jne no_sig 126 cmp setup_sig2,#SIG2 127 jne no_sig 128 jmp good_sig 129 130 no_sig: 131 lea si,no_sig_mess 132 call prtstr 133 no_sig_loop: 134 jmp no_sig_loop 135 136 good_sig: 137 mov ax,#INITSEG 138 mov ds,ax 139 140 ! Get memory size (extended mem, kB) 141 142 mov ah,#0x88 143 int 0x15 144 mov [2],ax 145 146 ! set the keyboard repeat rate to the max 147 148 mov ax,#0x0305 149 xor bx,bx ! clear bx 150 int 0x16 151 152 ! Check for video adapter and its parameters 153 ! Video mode selection is also handled here 154 155 call video 156 157 ! Get hd0 data 158 159 xor ax,ax ! clear ax 160 mov ds,ax 161 lds si,[4*0x41] 162 mov ax,#INITSEG 163 push ax 164 mov es,ax 165 mov di,#0x0080 166 mov cx,#0x10 167 push cx 168 cld 169 rep 170 movsb 171 172 ! Get hd1 data 173 174 xor ax,ax ! clear ax 175 mov ds,ax 176 lds si,[4*0x46] 177 pop cx 178 pop es 179 mov di,#0x0090 180 rep 181 movsb 182 183 ! Check that there IS a hd1 :-) 184 185 mov ax,#0x01500 186 mov dl,#0x81 187 int 0x13 188 jc no_disk1 189 cmp ah,#3 190 je is_disk1 191 no_disk1: 192 mov ax,#INITSEG 193 mov es,ax 194 mov di,#0x0090 195 mov cx,#0x10 196 xor ax,ax ! clear ax 197 cld 198 rep 199 stosb 200 is_disk1: 201 202 ! check for PS/2 pointing device 203 204 mov ax,#INITSEG 205 mov ds,ax 206 mov [0x1ff],#0 ! default is no pointing device 207 int 0x11 ! int 0x11: equipment determination 208 test al,#0x04 ! check if pointing device installed 209 jz no_psmouse 210 mov [0x1ff],#0xaa ! device present 211 no_psmouse: 212 ! now we want to move to protected mode ... 213 214 cli ! no interrupts allowed ! 215 mov al,#0x80 ! disable NMI for the bootup sequence 216 out #0x70,al 217 218 ! first we move the system to its rightful place 219 220 mov ax,#0x100 ! start of destination segment 221 seg cs 222 mov bx,start_sys_seg ! start of source segment 223 cld ! 'direction'=0, movs moves forward 224 do_move: 225 mov es,ax ! destination segment 226 inc ah ! instead of add ax,#0x100 227 cmp ax,#0x9000 228 jz end_move 229 mov ds,bx ! source segment 230 add bx,#0x100 231 sub di,di 232 sub si,si 233 mov cx,#0x800 234 rep 235 movsw 236 jmp do_move 237 238 ! then we load the segment descriptors 239 240 end_move: 241 mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-) 242 mov ds,ax 243 lidt idt_48 ! load idt with 0,0 244 lgdt gdt_48 ! load gdt with whatever appropriate 245 246 ! that was painless, now we enable A20 247 248 call empty_8042 249 mov al,#0xD1 ! command write 250 out #0x64,al 251 call empty_8042 252 mov al,#0xDF ! A20 on 253 out #0x60,al 254 call empty_8042 255 256 ! make sure any possible coprocessor is properly reset.. 257 258 xor ax,ax 259 out #0xf0,al 260 call delay 261 out #0xf1,al 262 call delay 263 264 ! well, that went ok, I hope. Now we have to reprogram the interrupts :-( 265 ! we put them right after the intel-reserved hardware interrupts, at 266 ! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really 267 ! messed this up with the original PC, and they haven't been able to 268 ! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, 269 ! which is used for the internal hardware interrupts as well. We just 270 ! have to reprogram the 8259's, and it isn't fun. 271 272 mov al,#0x11 ! initialization sequence 273 out #0x20,al ! send it to 8259A-1 274 call delay 275 out #0xA0,al ! and to 8259A-2 276 call delay 277 mov al,#0x20 ! start of hardware int's (0x20) 278 out #0x21,al 279 call delay 280 mov al,#0x28 ! start of hardware int's 2 (0x28) 281 out #0xA1,al 282 call delay 283 mov al,#0x04 ! 8259-1 is master 284 out #0x21,al 285 call delay 286 mov al,#0x02 ! 8259-2 is slave 287 out #0xA1,al 288 call delay 289 mov al,#0x01 ! 8086 mode for both 290 out #0x21,al 291 call delay 292 out #0xA1,al 293 call delay 294 mov al,#0xFF ! mask off all interrupts for now 295 out #0xA1,al 296 call delay 297 mov al,#0xFB ! mask all irq's but irq2 which 298 out #0x21,al ! is cascaded 299 300 ! well, that certainly wasn't fun :-(. Hopefully it works, and we don't 301 ! need no steenking BIOS anyway (except for the initial loading :-). 302 ! The BIOS-routine wants lots of unnecessary data, and it's less 303 ! "interesting" anyway. This is how REAL programmers do it. 304 ! 305 ! Well, now's the time to actually move into protected mode. To make 306 ! things as simple as possible, we do no register set-up or anything, 307 ! we let the gnu-compiled 32-bit programs do that. We just jump to 308 ! absolute address 0x10000, in 32-bit protected mode. 309 ! 310 ! Note that the short jump isn't strictly needed, although there are 311 ! reasons why it might be a good idea. It won't hurt in any case. 312 ! 313 mov ax,#1 ! protected mode (PE) bit 314 lmsw ax ! This is it! 315 jmp flush_instr 316 flush_instr: 317 xor bx,bx ! Flag to indicate a boot 318 jmpi 0x1000,KERNEL_CS ! jmp offset 1000 of segment 0x10 (cs) 319 320 ! This routine checks that the keyboard command queue is empty 321 ! (after emptying the output buffers) 322 ! 323 ! No timeout is used - if this hangs there is something wrong with 324 ! the machine, and we probably couldn't proceed anyway. 325 empty_8042: 326 call delay 327 in al,#0x64 ! 8042 status port 328 test al,#1 ! output buffer? 329 jz no_output 330 call delay 331 in al,#0x60 ! read it 332 jmp empty_8042 333 no_output: 334 test al,#2 ! is input buffer full? 335 jnz empty_8042 ! yes - loop 336 ret 337 338 ! 339 ! Delay is needed after doing i/o 340 ! 341 delay: 342 .word 0x00eb ! jmp $+2 343 ret 344 345 ! 346 ! Video card / mode detection. We do some hardware testing and build 347 ! a video mode list (placed directly after our code and data). Then we 348 ! choose the right mode given in the configuration or ask the user if 349 ! we are requested to do so. After all, all video parameters are stored 350 ! for later perusal by the kernel. 351 ! 352 353 video: movb [15],#0 ! Default is no VGA 354 mov ax,[0x01fa] 355 push ds 356 push ds 357 pop fs ! In this routine: FS=orig. DS 358 push cs 359 pop ds ! ES=DS=CS 360 push cs 361 pop es 362 mov modesave,ax 363 lea di,modelist ! ES:DI points to current item in our mode list 364 mov eax,#0x50190000 ! Store current mode: 80x25 365 cld 366 stosd 367 368 mov ah,#0x12 ! Check EGA/VGA 369 mov bl,#0x10 370 int 0x10 371 seg fs 372 mov [10],bx ! Used for identification of VGA in the kernel 373 cmp bl,#0x10 ! Not EGA nor VGA -> 80x25 only 374 je selmd1 375 376 mov eax,#0x5032FFFF ! EGA or VGA: 80x50 supported 377 stosd 378 379 mov ax,#0x1a00 ! Added check for EGA/VGA discrimination 380 int 0x10 381 cmp al,#0x1a ! 1a means VGA, anything else EGA 382 jne selmd1 383 seg fs 384 movb [15],#1 ! We've detected a VGA 385 386 mov eax,#0x501cFFFE ! VGA: 80x28 supported 387 stosd 388 389 lea si,vgatable ! Test all known SVGA adapters 390 dosvga: lodsw 391 mov bp,ax ! Default mode table 392 or ax,ax 393 jz didsv 394 lodsw ! Pointer to test routine 395 push si 396 push di 397 push es 398 mov bx,#0xc000 399 mov es,bx 400 call ax ! Call test routine 401 pop es 402 pop di 403 pop si 404 or bp,bp 405 jz dosvga 406 mov si,bp ! Found, copy the modes 407 mov ah,#0 408 cpsvga: lodsb 409 or al,al 410 jz didsv 411 stosw 412 movsw 413 jmp cpsvga 414 415 selmd1: jmp selmd 416 417 didsv: mov ax,#0x4f00 ! Fetch VESA information to ES:DI+0x400 418 add di,#0x400 419 int 0x10 420 sub di,#0x400 421 cmp al,#0x4f 422 jne selmd 423 lgs bx,(di+0x40e) 424 cmp (di+0x400),#0x4556 425 jne selmd 426 cmp (di+0x402),#0x4153 427 jne selmd 428 429 vesa1: seg gs 430 mov cx,(bx) 431 add bx,#2 432 cmp cx,#0xffff 433 je selmd 434 mov ax,#0x4f01 435 add di,#0xc00 436 int 0x10 437 sub di,#0xc00 438 cmp al,#0x4f 439 jne selmd 440 testb (di+0xc00),#0x10 ! Is it a text mode? 441 jne vesa1 442 testb (di+0xc00),#0x08 ! Has it colors? 443 je vesa1 444 mov dh,(di+0xc12) ! DX=dimensions, CX=mode 445 mov dl,(di+0xc14) 446 447 lea si,modelist ! Check if it's already on the list 448 vesa2: lodsw 449 lodsw 450 cmp ax,dx 451 je vesa1 452 cmp si,di 453 jc vesa2 454 455 mov ax,cx ! New mode, store it 456 stosw 457 mov ax,dx 458 stosw 459 jmp vesa1 460 461 ! 462 ! Video mode table built. Determine the mode we should use and set it. 463 ! 464 selmd: mov ax,modesave 465 cmp ax,#NORMAL_VGA ! Current mode (80x25) 466 je defmd1 467 cmp ax,#EXTENDED_VGA ! 80x50 mode 468 je try50 469 cmp ax,#ASK_VGA 470 jne usemd 471 banner: lea si,keymsg 472 call prtstr 473 call flush 474 nokey: call getkt 475 cmp al,#0x0d ! ENTER ? 476 je listm ! yes - manual mode selection 477 cmp al,#0x20 ! SPACE ? 478 je defmd1 ! no - repeat 479 call beep 480 jmp nokey 481 482 defmd1: br defmd 483 484 listm: call listmodes ! List all available modes 485 keymd: call getkey ! Get key representing mode ID 486 xor ah,ah 487 sub al,#0x30 488 jc keymd 489 cmp al,#10 490 jc usemd 491 sub al,#39 492 cmp al,#10 493 jc keymd 494 cmp al,#26 495 jnc keymd 496 jmp usemd 497 498 try50: mov ax,#1 ! 80x50 is mode #1 499 usemd: shl ax,#2 ! We're requested to set mode in AX 500 lea si,modelist 501 add si,ax 502 cmp si,di 503 jc mdok 504 cmp modesave,#ASK_VGA 505 je keymd 506 lea si,undefd 507 call prtstr 508 jmp banner 509 510 mdok: lodsw ! AX=mode number 511 cmp ah,#0xff 512 jz mdspec 513 or ax,ax 514 jz mdsetd 515 or ah,ah 516 jz mdset 517 mov bx,ax 518 mov ax,#0x4f02 519 mdset: int 0x10 520 mdsetd: lodsb ! AL=number of lines 521 jmp getpar 522 523 mdspec: inc ax ! Special modes 524 jz m80x50 525 526 m80x28: mov ax,#0x1111 ! Setting 80x28 (VGA with EGA font) 527 xor bl,bl 528 int 0x10 ! use 9x14 fontset (28 lines on VGA) 529 mov ah,#0x01 530 mov cx,#0x0b0c 531 int 0x10 ! turn on cursor (scan lines 11 to 12) 532 mov al,#28 533 jmp getpar 534 535 m80x50: mov ax,#0x1112 ! Setting 80x50 (EGA/VGA) 536 xor bl,bl 537 int 0x10 ! use 8x8 font set 538 mov ax,#0x1200 539 mov bl,#0x20 540 int 0x10 ! use alternate print screen 541 mov ax,#0x1201 542 mov bl,#0x34 543 int 0x10 ! turn off cursor emulation 544 mov ah,#0x01 545 mov cx,#0x0607 546 int 0x10 ! turn on cursor (scan lines 6 to 7) 547 mov al,#50 548 jmp getpar 549 550 defmd: mov al,#25 ! Default is 25 lines 551 552 ! 553 ! Correct video mode set. Determine the remaining parameters. 554 ! 555 556 getpar: pop ds ! Restore original DS 557 mov [14],al ! Number of lines 558 559 mov ah,#0x03 ! read cursor pos 560 xor bh,bh ! clear bh 561 int 0x10 ! save it in known place, con_init fetches 562 mov [0],dx ! it from 0x90000. 563 564 mov ah,#0x0f 565 int 0x10 566 mov [4],bx ! bh = display page 567 mov [6],ax ! al = video mode, ah = window width 568 xor ax,ax 569 mov es,ax ! Access low memory 570 seg es 571 mov ax,[0x485] ! POINTS - Height of character matrix 572 mov [16],ax 573 574 ret ! Well done... 575 576 ! 577 ! Table of all known SVGA cards. For each card, we store a pointer to 578 ! a table of video modes supported by the card and a pointer to a routine 579 ! used for testing of presence of the card. 580 ! 581 582 vgatable: 583 .word s3_md, s3_test 584 .word ati_md, ati_test 585 .word ahead_md, ahead_test 586 .word chips_md, chips_test 587 .word cirrus2_md, cirrus2_test 588 .word cirrus1_md, cirrus1_test 589 .word everex_md, everex_test 590 .word genoa_md, genoa_test 591 .word oak_md, oak_test 592 .word paradise_md, paradise_test 593 .word trident_md, trident_test 594 .word tseng_md, tseng_test 595 .word video7_md, video7_test 596 .word 0 597 598 ! 599 ! Test routines and mode tables: 600 ! 601 602 ! S3 - The test algorithm was taken from the SuperProbe package 603 ! for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org 604 605 s3_test: 606 mov cx,#0x0f35 ! we store some constants in cl/ch 607 mov dx,#0x03d4 608 movb al,#0x38 609 call inidx 610 mov bh,al ! store current value of CRT-register 0x38 611 mov ax,#0x0038 612 call outidx ! disable writing to special regs 613 movb al,cl ! check whether we can write special reg 0x35 614 call inidx 615 movb bl,al ! save the current value of CRT reg 0x35 616 andb al,#0xf0 ! clear bits 0-3 617 movb ah,al 618 movb al,cl ! and write it to CRT reg 0x35 619 call outidx 620 call inidx ! now read it back 621 andb al,ch ! clear the upper 4 bits 622 jz s3_2 ! the first test failed. But we have a 623 movb ah,bl ! second chance 624 mov al,cl 625 call outidx 626 jmp s3_1 ! do the other tests 627 s3_2: mov ax,cx ! load ah with 0xf and al with 0x35 628 orb ah,bl ! set the upper 4 bits of ah with the orig value 629 call outidx ! write ... 630 call inidx ! ... and reread 631 andb al,cl ! turn off the upper 4 bits 632 push ax 633 movb ah,bl ! restore old value in register 0x35 634 movb al,cl 635 call outidx 636 pop ax 637 cmp al,ch ! setting lower 4 bits was successful => bad 638 je no_s3 ! writing is allowed => this is not an S3 639 s3_1: mov ax,#0x4838 ! allow writing to special regs by putting 640 call outidx ! magic number into CRT-register 0x38 641 movb al,cl ! check whether we can write special reg 0x35 642 call inidx 643 movb bl,al 644 andb al,#0xf0 645 movb ah,al 646 movb al,cl 647 call outidx 648 call inidx 649 andb al,ch 650 jnz no_s3 ! no, we can't write => no S3 651 mov ax,cx 652 orb ah,bl 653 call outidx 654 call inidx 655 andb al,ch 656 push ax 657 movb ah,bl ! restore old value in register 0x35 658 movb al,cl 659 call outidx 660 pop ax 661 cmp al,ch 662 jne no_s31 ! writing not possible => no S3 663 movb al,#0x30 664 call inidx ! now get the S3 id ... 665 lea di,idS3 666 mov cx,#0x10 667 repne 668 scasb 669 je no_s31 670 movb ah,bh 671 movb al,#0x38 672 jmp s3rest 673 no_s3: movb al,#0x35 ! restore CRT register 0x35 674 movb ah,bl 675 call outidx 676 no_s31: xor bp,bp ! Detection failed 677 s3rest: movb ah,bh 678 movb al,#0x38 ! restore old value of CRT register 0x38 679 outidx: out dx,al ! Write to indexed VGA register 680 push ax ! AL=index, AH=data, DX=index reg port 681 mov al,ah 682 inc dx 683 out dx,al 684 dec dx 685 pop ax 686 ret 687 688 tstidx: out dx,ax ! OUT DX,AX and inidx 689 inidx: out dx,al ! Read from indexed VGA register 690 inc dx ! AL=index, DX=index reg port -> AL=data 691 in al,dx 692 dec dx 693 ret 694 695 idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 696 .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 697 698 s3_md: .byte 0x54, 0x2b, 0x84 699 .byte 0x55, 0x19, 0x84 700 .byte 0 701 702 ! ATI cards. 703 704 ati_test: 705 lea si,idati 706 mov di,#0x31 707 mov cx,#0x09 708 repe 709 cmpsb 710 je atiok 711 xor bp,bp 712 atiok: ret 713 714 idati: .ascii "761295520" 715 716 ati_md: .byte 0x23, 0x19, 0x84 717 .byte 0x33, 0x2c, 0x84 718 .byte 0x22, 0x1e, 0x64 719 .byte 0x21, 0x19, 0x64 720 .byte 0x58, 0x21, 0x50 721 .byte 0x5b, 0x1e, 0x50 722 .byte 0 723 724 ! AHEAD 725 726 ahead_test: 727 mov ax,#0x200f 728 mov dx,#0x3ce 729 out dx,ax 730 inc dx 731 in al,dx 732 cmp al,#0x20 733 je isahed 734 cmp al,#0x21 735 je isahed 736 xor bp,bp 737 isahed: ret 738 739 ahead_md: 740 .byte 0x22, 0x2c, 0x84 741 .byte 0x23, 0x19, 0x84 742 .byte 0x24, 0x1c, 0x84 743 .byte 0x2f, 0x32, 0xa0 744 .byte 0x32, 0x22, 0x50 745 .byte 0x34, 0x42, 0x50 746 .byte 0 747 748 ! Chips & Tech. 749 750 chips_test: 751 mov dx,#0x3c3 752 in al,dx 753 or al,#0x10 754 out dx,al 755 mov dx,#0x104 756 in al,dx 757 mov bl,al 758 mov dx,#0x3c3 759 in al,dx 760 and al,#0xef 761 out dx,al 762 cmp bl,#0xa5 763 je cantok 764 xor bp,bp 765 cantok: ret 766 767 chips_md: 768 .byte 0x60, 0x19, 0x84 769 .byte 0x61, 0x32, 0x84 770 .byte 0 771 772 ! Cirrus Logic 5X0 773 774 cirrus1_test: 775 mov dx,#0x3d4 776 mov al,#0x0c 777 out dx,al 778 inc dx 779 in al,dx 780 mov bl,al 781 xor al,al 782 out dx,al 783 dec dx 784 mov al,#0x1f 785 out dx,al 786 inc dx 787 in al,dx 788 mov bh,al 789 xor ah,ah 790 shl al,#4 791 mov cx,ax 792 mov al,bh 793 shr al,#4 794 add cx,ax 795 shl cx,#8 796 add cx,#6 797 mov ax,cx 798 mov dx,#0x3c4 799 out dx,ax 800 inc dx 801 in al,dx 802 and al,al 803 jnz nocirr 804 mov al,bh 805 out dx,al 806 in al,dx 807 cmp al,#0x01 808 je iscirr 809 nocirr: xor bp,bp 810 iscirr: mov dx,#0x3d4 811 mov al,bl 812 xor ah,ah 813 shl ax,#8 814 add ax,#0x0c 815 out dx,ax 816 ret 817 818 cirrus1_md: 819 .byte 0x1f, 0x19, 0x84 820 .byte 0x20, 0x2c, 0x84 821 .byte 0x22, 0x1e, 0x84 822 .byte 0x31, 0x25, 0x64 823 .byte 0 824 825 ! Cirrus Logic 54XX 826 827 cirrus2_test: 828 mov dx,#0x3c4 829 mov al,#6 830 call inidx 831 mov bl,al ! BL=backup 832 mov al,#6 833 xor ah,ah 834 call tstidx 835 cmp al,#0x0f 836 jne c2fail 837 mov ax,#0x1206 838 call tstidx 839 cmp al,#0x12 840 jne c2fail 841 mov al,#0x1e 842 call inidx 843 mov bh,al 844 and bh,#0xc0 845 mov ah,bh 846 mov al,#0x1e 847 call tstidx 848 xor al,bh 849 and al,#0x3f 850 jne c2xx 851 mov al,#0x1e 852 mov ah,bh 853 or ah,#0x3f 854 call tstidx 855 xor al,bh 856 xor al,#0x3f 857 and al,#0x3f 858 c2xx: pushf 859 mov al,#0x1e 860 mov ah,bh 861 out dx,ax 862 popf 863 je c2done 864 c2fail: xor bp,bp 865 c2done: mov al,#6 866 mov ah,bl 867 out dx,ax 868 ret 869 870 cirrus2_md: 871 .byte 0x14, 0x19, 0x84 872 .byte 0x54, 0x2b, 0x84 873 .byte 0 874 875 ! Everex / Trident 876 877 everex_test: 878 mov ax,#0x7000 879 xor bx,bx 880 int 0x10 881 cmp al,#0x70 882 jne noevrx 883 shr dx,#4 884 cmp dx,#0x678 885 je evtrid 886 cmp dx,#0x236 887 jne evrxok 888 evtrid: lea bp,trident_md 889 evrxok: ret 890 891 noevrx: xor bp,bp 892 ret 893 894 everex_md: 895 .byte 0x03, 0x22, 0x50 896 .byte 0x04, 0x3c, 0x50 897 .byte 0x07, 0x2b, 0x64 898 .byte 0x08, 0x4b, 0x64 899 .byte 0x0a, 0x19, 0x84 900 .byte 0x0b, 0x2c, 0x84 901 .byte 0x16, 0x1e, 0x50 902 .byte 0x18, 0x1b, 0x64 903 .byte 0x21, 0x40, 0xa0 904 .byte 0x40, 0x1e, 0x84 905 .byte 0 906 907 ! Genoa. 908 909 genoa_test: 910 lea si,idgenoa ! Check Genoa 'clues' 911 xor ax,ax 912 seg es 913 mov al,[0x37] 914 mov di,ax 915 mov cx,#0x04 916 dec si 917 dec di 918 l1: inc si 919 inc di 920 mov al,(si) 921 test al,al 922 jz l2 923 seg es 924 cmp al,(di) 925 l2: loope l1 926 or cx,cx 927 je isgen 928 xor bp,bp 929 isgen: ret 930 931 idgenoa: .byte 0x77, 0x00, 0x99, 0x66 932 933 genoa_md: 934 .byte 0x58, 0x20, 0x50 935 .byte 0x5a, 0x2a, 0x64 936 .byte 0x60, 0x19, 0x84 937 .byte 0x61, 0x1d, 0x84 938 .byte 0x62, 0x20, 0x84 939 .byte 0x63, 0x2c, 0x84 940 .byte 0x64, 0x3c, 0x84 941 .byte 0x6b, 0x4f, 0x64 942 .byte 0x72, 0x3c, 0x50 943 .byte 0x74, 0x42, 0x50 944 .byte 0x78, 0x4b, 0x64 945 .byte 0 946 947 ! OAK 948 949 oak_test: 950 lea si,idoakvga 951 mov di,#0x08 952 mov cx,#0x08 953 repe 954 cmpsb 955 je isoak 956 xor bp,bp 957 isoak: ret 958 959 idoakvga: .ascii "OAK VGA " 960 961 oak_md: .byte 0x4e, 0x3c, 0x50 962 .byte 0x4f, 0x3c, 0x84 963 .byte 0x50, 0x19, 0x84 964 .byte 0x51, 0x2b, 0x84 965 .byte 0 966 967 ! WD Paradise. 968 969 paradise_test: 970 lea si,idparadise 971 mov di,#0x7d 972 mov cx,#0x04 973 repe 974 cmpsb 975 je ispara 976 xor bp,bp 977 ispara: ret 978 979 idparadise: .ascii "VGA=" 980 981 paradise_md: 982 .byte 0x41, 0x22, 0x50 983 .byte 0x47, 0x1c, 0x84 984 .byte 0x55, 0x19, 0x84 985 .byte 0x54, 0x2c, 0x84 986 .byte 0 987 988 ! Trident. 989 990 trident_test: 991 mov dx,#0x3c4 992 mov al,#0x0e 993 out dx,al 994 inc dx 995 in al,dx 996 xchg ah,al 997 xor al,al 998 out dx,al 999 in al,dx 1000 xchg al,ah 1001 mov bl,al ! Strange thing ... in the book this wasn't 1002 and bl,#0x02 ! necessary but it worked on my card which 1003 jz setb2 ! is a trident. Without it the screen goes 1004 and al,#0xfd ! blurred ... 1005 jmp clrb2 ! 1006 setb2: or al,#0x02 ! 1007 clrb2: out dx,al 1008 and ah,#0x0f 1009 cmp ah,#0x02 1010 je istrid 1011 xor bp,bp 1012 istrid: ret 1013 1014 trident_md: 1015 .byte 0x50, 0x1e, 0x50 1016 .byte 0x51, 0x2b, 0x50 1017 .byte 0x52, 0x3c, 0x50 1018 .byte 0x57, 0x19, 0x84 1019 .byte 0x58, 0x1e, 0x84 1020 .byte 0x59, 0x2b, 0x84 1021 .byte 0x5a, 0x3c, 0x84 1022 .byte 0 1023 1024 ! Tseng. 1025 1026 tseng_test: 1027 mov dx,#0x3cd 1028 in al,dx ! Could things be this simple ! :-) 1029 mov bl,al 1030 mov al,#0x55 1031 out dx,al 1032 in al,dx 1033 mov ah,al 1034 mov al,bl 1035 out dx,al 1036 cmp ah,#0x55 1037 je istsen 1038 xor bp,bp 1039 istsen: ret 1040 1041 tseng_md: 1042 .byte 0x26, 0x3c, 0x50 1043 .byte 0x2a, 0x28, 0x64 1044 .byte 0x23, 0x19, 0x84 1045 .byte 0x24, 0x1c, 0x84 1046 .byte 0x22, 0x2c, 0x84 1047 .byte 0 1048 1049 ! Video7. 1050 1051 video7_test: 1052 mov dx,#0x3cc 1053 in al,dx 1054 mov dx,#0x3b4 1055 and al,#0x01 1056 jz even7 1057 mov dx,#0x3d4 1058 even7: mov al,#0x0c 1059 out dx,al 1060 inc dx 1061 in al,dx 1062 mov bl,al 1063 mov al,#0x55 1064 out dx,al 1065 in al,dx 1066 dec dx 1067 mov al,#0x1f 1068 out dx,al 1069 inc dx 1070 in al,dx 1071 mov bh,al 1072 dec dx 1073 mov al,#0x0c 1074 out dx,al 1075 inc dx 1076 mov al,bl 1077 out dx,al 1078 mov al,#0x55 1079 xor al,#0xea 1080 cmp al,bh 1081 je isvid7 1082 xor bp,bp 1083 isvid7: ret 1084 1085 video7_md: 1086 .byte 0x40, 0x2b, 0x50 1087 .byte 0x43, 0x3c, 0x50 1088 .byte 0x44, 0x3c, 0x64 1089 .byte 0x41, 0x19, 0x84 1090 .byte 0x42, 0x2c, 0x84 1091 .byte 0x45, 0x1c, 0x84 1092 .byte 0 1093 1094 ! 1095 ! Displaying of the mode list. 1096 ! 1097 1098 listmodes: 1099 lea si,listhdr 1100 call prtstr 1101 lea bx,modelist 1102 mov cl,#0x30 1103 listm1: mov modenr,cl 1104 lea si,modestring 1105 call prtstr 1106 mov al,(bx+3) 1107 call dprnt 1108 mov al,#0x78 1109 call prnt1 1110 mov al,(bx+2) 1111 call dprnt 1112 #ifdef SHOW_BIOS_MODES 1113 mov al,#0x20 1114 call prnt1 1115 mov al,#0x28 1116 call prnt1 1117 mov al,(bx+1) 1118 call prthex 1119 mov al,(bx) 1120 call prthex 1121 mov al,#0x29 1122 call prnt1 1123 #endif 1124 lea si,crlf 1125 call prtstr 1126 add bx,#4 1127 inc cl 1128 cmp cl,#0x3a 1129 jnz listm2 1130 mov cl,#0x61 1131 listm2: cmp bx,di 1132 jc listm1 1133 lea si,prompt 1134 br prtstr 1135 1136 ! Routine to print a hexadecimal byte (AL) on screen. 1137 1138 #ifdef SHOW_BIOS_MODES 1139 prthex: push ax 1140 shr al,#4 1141 call prth1 1142 pop ax 1143 prth1: and al,#15 1144 cmp al,#10 1145 jc prth2 1146 add al,#7 1147 prth2: add al,#0x30 1148 br prnt1 1149 #endif 1150 1151 ! Routine to print a decimal value on screen, the value to be 1152 ! printed is put in AL (i.e 0-255). 1153 1154 dprnt: push ax 1155 push cx 1156 xor ah,ah ! Clear ah 1157 mov cl,#0x0a 1158 idiv cl 1159 cmp al,#0x09 1160 jbe lt100 1161 call dprnt 1162 jmp skip10 1163 lt100: add al,#0x30 1164 call prnt1 1165 skip10: mov al,ah 1166 add al,#0x30 1167 call prnt1 1168 pop cx 1169 pop ax 1170 ret 1171 1172 ! 1173 ! Read a key and return the (US-)ascii code in al, scan code in ah 1174 ! 1175 getkey: 1176 xor ah,ah 1177 int 0x16 1178 ret 1179 1180 ! 1181 ! Read a key with a timeout of 30 seconds. The cmos clock is used to get 1182 ! the time. 1183 ! 1184 getkt: 1185 call gettime 1186 add al,#30 ! wait 30 seconds 1187 cmp al,#60 1188 jl lminute 1189 sub al,#60 1190 lminute: 1191 mov cl,al 1192 again: mov ah,#0x01 1193 int 0x16 1194 jnz getkey ! key pressed, so get it 1195 call gettime 1196 cmp al,cl 1197 jne again 1198 mov al,#0x20 ! timeout, return default char `space' 1199 ret 1200 1201 ! 1202 ! Flush the keyboard buffer 1203 ! 1204 flush: mov ah,#0x01 1205 int 0x16 1206 jz empty 1207 xor ah,ah 1208 int 0x16 1209 jmp flush 1210 empty: ret 1211 1212 ! 1213 ! Read the cmos clock. Return the seconds in al 1214 ! 1215 gettime: 1216 push cx 1217 mov ah,#0x02 1218 int 0x1a 1219 mov al,dh ! dh contains the seconds 1220 and al,#0x0f 1221 mov ah,dh 1222 mov cl,#0x04 1223 shr ah,cl 1224 aad 1225 pop cx 1226 ret 1227 1228 ! 1229 ! Descriptor table for our protected mode transition. 1230 ! 1231 1232 gdt: 1233 .word 0,0,0,0 ! dummy 1234 1235 .word 0,0,0,0 ! unused 1236 1237 .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) 1238 .word 0x0000 ! base address=0 1239 .word 0x9A00 ! code read/exec 1240 .word 0x00C0 ! granularity=4096, 386 1241 1242 .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) 1243 .word 0x0000 ! base address=0 1244 .word 0x9200 ! data read/write 1245 .word 0x00C0 ! granularity=4096, 386 1246 1247 idt_48: 1248 .word 0 ! idt limit=0 1249 .word 0,0 ! idt base=0L 1250 1251 gdt_48: 1252 .word 0x800 ! gdt limit=2048, 256 GDT entries 1253 .word 512+gdt,0x9 ! gdt base = 0X9xxxx 1254 1255 ! 1256 ! Assorted messages. 1257 ! 1258 1259 keymsg: .ascii "Press <RETURN> to see video modes available, <SPACE> to continue or wait 30 secs" 1260 db 0x0d, 0x0a, 0x00 1261 listhdr: .ascii "Mode: COLSxROWS:" 1262 db 0x0d, 0x0a, 0x0a, 0x00 1263 prompt: db 0x0d, 0x0a 1264 .ascii "Choose mode by pressing the corresponding number or letter." 1265 crlf: db 0x0d, 0x0a, 0x00 1266 undefd: .ascii "You passed an undefined mode number to setup. Please choose a new mode." 1267 db 0x0d, 0x0a, 0x0a, 0x07, 0x00 1268 modestring: .ascii " " 1269 modenr: db 0x00 ! mode number 1270 .ascii ": " 1271 db 0x00 1272 1273 modesave: .word 0 ! Requsted mode ID. 1274 1275 ! This must be last 1276 setup_sig1: .word SIG1 1277 setup_sig2: .word SIG2 1278 1279 ! After our code and data, we'll store the mode list. 1280 ! Mode record: .word modenr 1281 ! .byte lines 1282 ! .byte columns 1283 ! Mode numbers used: 0=current, >=0x100=VESA, -1=80x50, -2=80x28 1284 modelist: 1285 1286 .text 1287 endtext: 1288 .data 1289 enddata: 1290 .bss 1291 endbss: