| ! |
| ! setup.s (C) 1991 Linus Torvalds |
| ! |
| ! setup.s is responsible for getting the system data from the BIOS, |
| ! and putting them into the appropriate places in system memory. |
| ! both setup.s and system has been loaded by the bootblock. |
| ! |
| ! This code asks the bios for memory/disk/other parameters, and |
| ! puts them in a "safe" place: 0x90000-0x901FF, ie where the |
| ! boot-block used to be. It is then up to the protected mode |
| ! system to read them from there before the area is overwritten |
| ! for buffer-blocks. |
| ! |
| |
| ! NOTE! These had better be the same as in bootsect.s! |
| #include <linux/config.h> |
| |
| INITSEG = DEF_INITSEG ! we move boot here - out of the way |
| SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). |
| SETUPSEG = DEF_SETUPSEG ! this is the current segment |
| |
| .globl begtext, begdata, begbss, endtext, enddata, endbss |
| .text |
| begtext: |
| .data |
| begdata: |
| .bss |
| begbss: |
| .text |
| |
| entry start |
| start: |
| |
| ! ok, the read went well so we get current cursor position and save it for |
| ! posterity. |
| |
| mov ax,#INITSEG ! this is done in bootsect already, but... |
| mov ds,ax |
| |
| ! Get memory size (extended mem, kB) |
| |
| mov ah,#0x88 |
| int 0x15 |
| mov [2],ax |
| |
| ! set the keyboard repeat rate to the max |
| |
| mov ax,#0x0305 |
| mov bx,#0x0000 |
| int 0x16 |
| |
| ! check for EGA/VGA and some config parameters |
| |
| mov ah,#0x12 |
| mov bl,#0x10 |
| int 0x10 |
| mov [8],ax |
| mov [10],bx |
| mov [12],cx |
| mov ax,#0x5019 |
| cmp bl,#0x10 |
| je novga |
| call chsvga |
| novga: mov [14],ax |
| mov ah,#0x03 ! read cursor pos |
| xor bh,bh |
| int 0x10 ! save it in known place, con_init fetches |
| mov [0],dx ! it from 0x90000. |
| |
| ! Get video-card data: |
| |
| mov ah,#0x0f |
| int 0x10 |
| mov [4],bx ! bh = display page |
| mov [6],ax ! al = video mode, ah = window width |
| |
| ! Get hd0 data |
| |
| mov ax,#0x0000 |
| mov ds,ax |
| lds si,[4*0x41] |
| mov ax,#INITSEG |
| mov es,ax |
| mov di,#0x0080 |
| mov cx,#0x10 |
| cld |
| rep |
| movsb |
| |
| ! Get hd1 data |
| |
| mov ax,#0x0000 |
| mov ds,ax |
| lds si,[4*0x46] |
| mov ax,#INITSEG |
| mov es,ax |
| mov di,#0x0090 |
| mov cx,#0x10 |
| cld |
| rep |
| movsb |
| |
| ! Check that there IS a hd1 :-) |
| |
| mov ax,#0x01500 |
| mov dl,#0x81 |
| int 0x13 |
| jc no_disk1 |
| cmp ah,#3 |
| je is_disk1 |
| no_disk1: |
| mov ax,#INITSEG |
| mov es,ax |
| mov di,#0x0090 |
| mov cx,#0x10 |
| mov ax,#0x00 |
| cld |
| rep |
| stosb |
| is_disk1: |
| |
| ! now we want to move to protected mode ... |
| |
| cli ! no interrupts allowed ! |
| |
| ! first we move the system to it's rightful place |
| |
| mov ax,#0x0000 |
| cld ! 'direction'=0, movs moves forward |
| do_move: |
| mov es,ax ! destination segment |
| add ax,#0x1000 |
| cmp ax,#0x9000 |
| jz end_move |
| mov ds,ax ! source segment |
| sub di,di |
| sub si,si |
| mov cx,#0x8000 |
| rep |
| movsw |
| jmp do_move |
| |
| ! then we load the segment descriptors |
| |
| end_move: |
| mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-) |
| mov ds,ax |
| lidt idt_48 ! load idt with 0,0 |
| lgdt gdt_48 ! load gdt with whatever appropriate |
| |
| ! that was painless, now we enable A20 |
| |
| call empty_8042 |
| mov al,#0xD1 ! command write |
| out #0x64,al |
| call empty_8042 |
| mov al,#0xDF ! A20 on |
| out #0x60,al |
| call empty_8042 |
| |
| ! well, that went ok, I hope. Now we have to reprogram the interrupts :-( |
| ! we put them right after the intel-reserved hardware interrupts, at |
| ! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really |
| ! messed this up with the original PC, and they haven't been able to |
| ! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, |
| ! which is used for the internal hardware interrupts as well. We just |
| ! have to reprogram the 8259's, and it isn't fun. |
| |
| mov al,#0x11 ! initialization sequence |
| out #0x20,al ! send it to 8259A-1 |
| .word 0x00eb,0x00eb ! jmp $+2, jmp $+2 |
| out #0xA0,al ! and to 8259A-2 |
| .word 0x00eb,0x00eb |
| mov al,#0x20 ! start of hardware int's (0x20) |
| out #0x21,al |
| .word 0x00eb,0x00eb |
| mov al,#0x28 ! start of hardware int's 2 (0x28) |
| out #0xA1,al |
| .word 0x00eb,0x00eb |
| mov al,#0x04 ! 8259-1 is master |
| out #0x21,al |
| .word 0x00eb,0x00eb |
| mov al,#0x02 ! 8259-2 is slave |
| out #0xA1,al |
| .word 0x00eb,0x00eb |
| mov al,#0x01 ! 8086 mode for both |
| out #0x21,al |
| .word 0x00eb,0x00eb |
| out #0xA1,al |
| .word 0x00eb,0x00eb |
| mov al,#0xFF ! mask off all interrupts for now |
| out #0x21,al |
| .word 0x00eb,0x00eb |
| out #0xA1,al |
| |
| ! well, that certainly wasn't fun :-(. Hopefully it works, and we don't |
| ! need no steenking BIOS anyway (except for the initial loading :-). |
| ! The BIOS-routine wants lots of unnecessary data, and it's less |
| ! "interesting" anyway. This is how REAL programmers do it. |
| ! |
| ! Well, now's the time to actually move into protected mode. To make |
| ! things as simple as possible, we do no register set-up or anything, |
| ! we let the gnu-compiled 32-bit programs do that. We just jump to |
| ! absolute address 0x00000, in 32-bit protected mode. |
| |
| mov ax,#0x0001 ! protected mode (PE) bit |
| lmsw ax ! This is it! |
| jmpi 0,8 ! jmp offset 0 of segment 8 (cs) |
| |
| ! This routine checks that the keyboard command queue is empty |
| ! No timeout is used - if this hangs there is something wrong with |
| ! the machine, and we probably couldn't proceed anyway. |
| empty_8042: |
| .word 0x00eb,0x00eb |
| in al,#0x64 ! 8042 status port |
| test al,#2 ! is input buffer full? |
| jnz empty_8042 ! yes - loop |
| ret |
| |
| ! Routine trying to recognize type of SVGA-board present (if any) |
| ! and if it recognize one gives the choices of resolution it offers. |
| ! If one is found the resolution chosen is given by al,ah (rows,cols). |
| |
| chsvga: cld |
| push ds |
| push cs |
| pop ds |
| mov ax,#0xc000 |
| mov es,ax |
| lea si,msg1 |
| call prtstr |
| flush: in al,#0x60 ! Flush the keyboard buffer |
| cmp al,#0x82 |
| jb nokey |
| jmp flush |
| nokey: in al,#0x60 |
| cmp al,#0x82 |
| jb nokey |
| cmp al,#0xe0 |
| ja nokey |
| cmp al,#0x9c |
| je svga |
| mov ax,#0x5019 |
| pop ds |
| ret |
| svga: cld |
| lea si,idati ! Check ATI 'clues' |
| mov di,#0x31 |
| mov cx,#0x09 |
| repe |
| cmpsb |
| jne noati |
| lea si,dscati |
| lea di,moati |
| lea cx,selmod |
| jmp cx |
| noati: mov ax,#0x200f ! Check Ahead 'clues' |
| mov dx,#0x3ce |
| out dx,ax |
| inc dx |
| in al,dx |
| cmp al,#0x20 |
| je isahed |
| cmp al,#0x21 |
| jne noahed |
| isahed: lea si,dscahead |
| lea di,moahead |
| lea cx,selmod |
| jmp cx |
| noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues' |
| in al,dx |
| or al,#0x10 |
| out dx,al |
| mov dx,#0x104 |
| in al,dx |
| mov bl,al |
| mov dx,#0x3c3 |
| in al,dx |
| and al,#0xef |
| out dx,al |
| cmp bl,[idcandt] |
| jne nocant |
| lea si,dsccandt |
| lea di,mocandt |
| lea cx,selmod |
| jmp cx |
| nocant: mov dx,#0x3d4 ! Check Cirrus 'clues' |
| mov al,#0x0c |
| out dx,al |
| inc dx |
| in al,dx |
| mov bl,al |
| xor al,al |
| out dx,al |
| dec dx |
| mov al,#0x1f |
| out dx,al |
| inc dx |
| in al,dx |
| mov bh,al |
| xor ah,ah |
| shl al,#4 |
| mov cx,ax |
| mov al,bh |
| shr al,#4 |
| add cx,ax |
| shl cx,#8 |
| add cx,#6 |
| mov ax,cx |
| mov dx,#0x3c4 |
| out dx,ax |
| inc dx |
| in al,dx |
| and al,al |
| jnz nocirr |
| mov al,bh |
| out dx,al |
| in al,dx |
| cmp al,#0x01 |
| jne nocirr |
| call rst3d4 |
| lea si,dsccirrus |
| lea di,mocirrus |
| lea cx,selmod |
| jmp cx |
| rst3d4: mov dx,#0x3d4 |
| mov al,bl |
| xor ah,ah |
| shl ax,#8 |
| add ax,#0x0c |
| out dx,ax |
| ret |
| nocirr: call rst3d4 ! Check Everex 'clues' |
| mov ax,#0x7000 |
| xor bx,bx |
| int 0x10 |
| cmp al,#0x70 |
| jne noevrx |
| shr dx,#4 |
| cmp dx,#0x678 |
| je istrid |
| cmp dx,#0x236 |
| je istrid |
| lea si,dsceverex |
| lea di,moeverex |
| lea cx,selmod |
| jmp cx |
| istrid: lea cx,ev2tri |
| jmp cx |
| noevrx: lea si,idgenoa ! Check Genoa 'clues' |
| xor ax,ax |
| seg es |
| mov al,[0x37] |
| mov di,ax |
| mov cx,#0x04 |
| dec si |
| dec di |
| l1: inc si |
| inc di |
| mov al,(si) |
| seg es |
| and al,(di) |
| cmp al,(si) |
| loope l1 |
| cmp cx,#0x00 |
| jne nogen |
| lea si,dscgenoa |
| lea di,mogenoa |
| lea cx,selmod |
| jmp cx |
| nogen: cld |
| lea si,idparadise ! Check Paradise 'clues' |
| mov di,#0x7d |
| mov cx,#0x04 |
| repe |
| cmpsb |
| jne nopara |
| lea si,dscparadise |
| lea di,moparadise |
| lea cx,selmod |
| jmp cx |
| nopara: mov dx,#0x3c4 ! Check Trident 'clues' |
| mov al,#0x0e |
| out dx,al |
| inc dx |
| in al,dx |
| xchg ah,al |
| mov al,#0x00 |
| out dx,al |
| in al,dx |
| xchg al,ah |
| mov bl,al ! Strange thing ... in the book this wasn't |
| and bl,#0x02 ! necessary but it worked on my card which |
| jz setb2 ! is a trident. Without it the screen goes |
| and al,#0xfd ! blurred ... |
| jmp clrb2 ! |
| setb2: or al,#0x02 ! |
| clrb2: out dx,al |
| and ah,#0x0f |
| cmp ah,#0x02 |
| jne notrid |
| ev2tri: lea si,dsctrident |
| lea di,motrident |
| lea cx,selmod |
| jmp cx |
| notrid: mov dx,#0x3cd ! Check Tseng 'clues' |
| in al,dx ! Could things be this simple ! :-) |
| mov bl,al |
| mov al,#0x55 |
| out dx,al |
| in al,dx |
| mov ah,al |
| mov al,bl |
| out dx,al |
| cmp ah,#0x55 |
| jne notsen |
| lea si,dsctseng |
| lea di,motseng |
| lea cx,selmod |
| jmp cx |
| notsen: mov dx,#0x3cc ! Check Video7 'clues' |
| in al,dx |
| mov dx,#0x3b4 |
| and al,#0x01 |
| jz even7 |
| mov dx,#0x3d4 |
| even7: mov al,#0x0c |
| out dx,al |
| inc dx |
| in al,dx |
| mov bl,al |
| mov al,#0x55 |
| out dx,al |
| in al,dx |
| dec dx |
| mov al,#0x1f |
| out dx,al |
| inc dx |
| in al,dx |
| mov bh,al |
| dec dx |
| mov al,#0x0c |
| out dx,al |
| inc dx |
| mov al,bl |
| out dx,al |
| mov al,#0x55 |
| xor al,#0xea |
| cmp al,bh |
| jne novid7 |
| lea si,dscvideo7 |
| lea di,movideo7 |
| selmod: push si |
| lea si,msg2 |
| call prtstr |
| xor cx,cx |
| mov cl,(di) |
| pop si |
| push si |
| push cx |
| tbl: pop bx |
| push bx |
| mov al,bl |
| sub al,cl |
| call dprnt |
| call spcing |
| lodsw |
| xchg al,ah |
| call dprnt |
| xchg ah,al |
| push ax |
| mov al,#0x78 |
| call prnt1 |
| pop ax |
| call dprnt |
| call docr |
| loop tbl |
| pop cx |
| call docr |
| lea si,msg3 |
| call prtstr |
| pop si |
| add cl,#0x80 |
| nonum: in al,#0x60 ! Quick and dirty... |
| cmp al,#0x82 |
| jb nonum |
| cmp al,#0x8b |
| je zero |
| cmp al,cl |
| ja nonum |
| jmp nozero |
| zero: sub al,#0x0a |
| nozero: sub al,#0x80 |
| dec al |
| xor ah,ah |
| add di,ax |
| inc di |
| push ax |
| mov al,(di) |
| int 0x10 |
| pop ax |
| shl ax,#1 |
| add si,ax |
| lodsw |
| pop ds |
| ret |
| novid7: |
| mov ax,#0x1112 |
| mov bl,#0 |
| int 0x10 ! use 8x8 font set (50 lines on VGA) |
| |
| mov ax,#0x1200 |
| mov bl,#0x20 |
| int 0x10 ! use alternate print screen |
| |
| mov ax,#0x1201 |
| mov bl,#0x34 |
| int 0x10 ! turn off cursor emulation |
| |
| mov ah,#0x01 |
| mov cx,#0x0607 |
| int 0x10 ! turn on cursor (scan lines 6 to 7) |
| |
| pop ds |
| mov ax,#0x5032 ! return 80x50 |
| ret |
| |
| ! Routine that 'tabs' to next col. |
| |
| spcing: mov al,#0x2e |
| call prnt1 |
| mov al,#0x20 |
| call prnt1 |
| mov al,#0x20 |
| call prnt1 |
| mov al,#0x20 |
| call prnt1 |
| mov al,#0x20 |
| call prnt1 |
| ret |
| |
| ! Routine to print asciiz-string at DS:SI |
| |
| prtstr: lodsb |
| and al,al |
| jz fin |
| call prnt1 |
| jmp prtstr |
| fin: ret |
| |
| ! Routine to print a decimal value on screen, the value to be |
| ! printed is put in al (i.e 0-255). |
| |
| dprnt: push ax |
| push cx |
| mov ah,#0x00 |
| mov cl,#0x0a |
| idiv cl |
| cmp al,#0x09 |
| jbe lt100 |
| call dprnt |
| jmp skip10 |
| lt100: add al,#0x30 |
| call prnt1 |
| skip10: mov al,ah |
| add al,#0x30 |
| call prnt1 |
| pop cx |
| pop ax |
| ret |
| |
| ! Part of above routine, this one just prints ascii al |
| |
| prnt1: push ax |
| push cx |
| mov bh,#0x00 |
| mov cx,#0x01 |
| mov ah,#0x0e |
| int 0x10 |
| pop cx |
| pop ax |
| ret |
| |
| ! Prints <CR> + <LF> |
| |
| docr: push ax |
| push cx |
| mov bh,#0x00 |
| mov ah,#0x0e |
| mov al,#0x0a |
| mov cx,#0x01 |
| int 0x10 |
| mov al,#0x0d |
| int 0x10 |
| pop cx |
| pop ax |
| ret |
| |
| gdt: |
| .word 0,0,0,0 ! dummy |
| |
| .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) |
| .word 0x0000 ! base address=0 |
| .word 0x9A00 ! code read/exec |
| .word 0x00C0 ! granularity=4096, 386 |
| |
| .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) |
| .word 0x0000 ! base address=0 |
| .word 0x9200 ! data read/write |
| .word 0x00C0 ! granularity=4096, 386 |
| |
| idt_48: |
| .word 0 ! idt limit=0 |
| .word 0,0 ! idt base=0L |
| |
| gdt_48: |
| .word 0x800 ! gdt limit=2048, 256 GDT entries |
| .word 512+gdt,0x9 ! gdt base = 0X9xxxx |
| |
| msg1: .ascii "Press <RETURN> to see SVGA-modes available or any other key to continue." |
| db 0x0d, 0x0a, 0x0a, 0x00 |
| msg2: .ascii "Mode: COLSxROWS:" |
| db 0x0d, 0x0a, 0x0a, 0x00 |
| msg3: .ascii "Choose mode by pressing the corresponding number." |
| db 0x0d, 0x0a, 0x00 |
| |
| idati: .ascii "761295520" |
| idcandt: .byte 0xa5 |
| idgenoa: .byte 0x77, 0x00, 0x66, 0x99 |
| idparadise: .ascii "VGA=" |
| |
| ! Manufacturer: Numofmodes: Mode: |
| |
| moati: .byte 0x02, 0x23, 0x33 |
| moahead: .byte 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34 |
| mocandt: .byte 0x02, 0x60, 0x61 |
| mocirrus: .byte 0x04, 0x1f, 0x20, 0x22, 0x31 |
| moeverex: .byte 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40 |
| mogenoa: .byte 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78 |
| moparadise: .byte 0x02, 0x55, 0x54 |
| motrident: .byte 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a |
| motseng: .byte 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22 |
| movideo7: .byte 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45 |
| |
| ! msb = Cols lsb = Rows: |
| |
| dscati: .word 0x8419, 0x842c |
| dscahead: .word 0x842c, 0x8419, 0x841c, 0xa032, 0x5042 |
| dsccandt: .word 0x8419, 0x8432 |
| dsccirrus: .word 0x8419, 0x842c, 0x841e, 0x6425 |
| dsceverex: .word 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e |
| dscgenoa: .word 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b |
| dscparadise: .word 0x8419, 0x842b |
| dsctrident: .word 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c |
| dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c |
| dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c |
| |
| .text |
| endtext: |
| .data |
| enddata: |
| .bss |
| endbss: |