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 17 INITSEG = 0x9000 | we move boot here - out of the way 18 SYSSEG = 0x1000 | system loaded at 0x10000 (65536). 19 SETUPSEG = 0x9020 | this is the current segment 20 21 .globl begtext, begdata, begbss, endtext, enddata, endbss 22 .text 23 begtext: 24 .data 25 begdata: 26 .bss 27 begbss: 28 .text 29 30 entry start 31 start: 32 33 | ok, the read went well so we get current cursor position and save it for 34 | posterity. 35 36 mov ax,#INITSEG | this is done in bootsect already, but... 37 mov ds,ax 38 mov ah,#0x03 | read cursor pos 39 xor bh,bh 40 int 0x10 | save it in known place, con_init fetches 41 mov [0],dx | it from 0x90000. 42 43 | Get memory size (extended mem, kB) 44 45 mov ah,#0x88 46 int 0x15 47 mov [2],ax 48 49 | Get hd0 data 50 51 mov ax,#0x0000 52 mov ds,ax 53 lds si,[4*0x41] 54 mov ax,#INITSEG 55 mov es,ax 56 mov di,#0x0080 57 mov cx,#0x10 58 rep 59 movsb 60 61 | Get hd1 data 62 63 mov ax,#0x0000 64 mov ds,ax 65 lds si,[4*0x46] 66 mov ax,#INITSEG 67 mov es,ax 68 mov di,#0x0090 69 mov cx,#0x10 70 rep 71 movsb 72 73 | Check that there IS a hd1 :-) 74 75 mov ax,#0x01500 76 mov dl,#0x81 77 int 0x13 78 jc no_disk1 79 cmp ah,#3 80 je is_disk1 81 no_disk1: 82 mov ax,#INITSEG 83 mov es,ax 84 mov di,#0x0090 85 mov cx,#0x10 86 mov ax,#0x00 87 rep 88 stosb 89 is_disk1: 90 91 | now we want to move to protected mode ... 92 93 cli | no interrupts allowed ! 94 95 | first we move the system to it's rightful place 96 97 mov ax,#0x0000 98 cld | 'direction'=0, movs moves forward 99 do_move: 100 mov es,ax | destination segment 101 add ax,#0x1000 102 cmp ax,#0x9000 103 jz end_move 104 mov ds,ax | source segment 105 sub di,di 106 sub si,si 107 mov cx,#0x8000 108 rep 109 movsw 110 jmp do_move 111 112 | then we load the segment descriptors 113 114 end_move: 115 mov ax,#SETUPSEG | right, forgot this at first. didn't work :-) 116 mov ds,ax 117 lidt idt_48 | load idt with 0,0 118 lgdt gdt_48 | load gdt with whatever appropriate 119 120 | that was painless, now we enable A20 121 122 call empty_8042 123 mov al,#0xD1 | command write 124 out #0x64,al 125 call empty_8042 126 mov al,#0xDF | A20 on 127 out #0x60,al 128 call empty_8042 129 130 | well, that went ok, I hope. Now we have to reprogram the interrupts :-( 131 | we put them right after the intel-reserved hardware interrupts, at 132 | int 0x20-0x2F. There they won't mess up anything. Sadly IBM really 133 | messed this up with the original PC, and they haven't been able to 134 | rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, 135 | which is used for the internal hardware interrupts as well. We just 136 | have to reprogram the 8259's, and it isn't fun. 137 138 mov al,#0x11 | initialization sequence 139 out #0x20,al | send it to 8259A-1 140 .word 0x00eb,0x00eb | jmp $+2, jmp $+2 141 out #0xA0,al | and to 8259A-2 142 .word 0x00eb,0x00eb 143 mov al,#0x20 | start of hardware int's (0x20) 144 out #0x21,al 145 .word 0x00eb,0x00eb 146 mov al,#0x28 | start of hardware int's 2 (0x28) 147 out #0xA1,al 148 .word 0x00eb,0x00eb 149 mov al,#0x04 | 8259-1 is master 150 out #0x21,al 151 .word 0x00eb,0x00eb 152 mov al,#0x02 | 8259-2 is slave 153 out #0xA1,al 154 .word 0x00eb,0x00eb 155 mov al,#0x01 | 8086 mode for both 156 out #0x21,al 157 .word 0x00eb,0x00eb 158 out #0xA1,al 159 .word 0x00eb,0x00eb 160 mov al,#0xFF | mask off all interrupts for now 161 out #0x21,al 162 .word 0x00eb,0x00eb 163 out #0xA1,al 164 165 | well, that certainly wasn't fun :-(. Hopefully it works, and we don't 166 | need no steenking BIOS anyway (except for the initial loading :-). 167 | The BIOS-routine wants lots of unnecessary data, and it's less 168 | "interesting" anyway. This is how REAL programmers do it. 169 | 170 | Well, now's the time to actually move into protected mode. To make 171 | things as simple as possible, we do no register set-up or anything, 172 | we let the gnu-compiled 32-bit programs do that. We just jump to 173 | absolute address 0x00000, in 32-bit protected mode. 174 175 mov ax,#0x0001 | protected mode (PE) bit 176 lmsw ax | This is it! 177 jmpi 0,8 | jmp offset 0 of segment 8 (cs) 178 179 | This routine checks that the keyboard command queue is empty 180 | No timeout is used - if this hangs there is something wrong with 181 | the machine, and we probably couldn't proceed anyway. 182 empty_8042: 183 .word 0x00eb,0x00eb 184 in al,#0x64 | 8042 status port 185 test al,#2 | is input buffer full? 186 jnz empty_8042 | yes - loop 187 ret 188 189 gdt: 190 .word 0,0,0,0 | dummy 191 192 .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb) 193 .word 0x0000 | base address=0 194 .word 0x9A00 | code read/exec 195 .word 0x00C0 | granularity=4096, 386 196 197 .word 0x07FF | 8Mb - limit=2047 (2048*4096=8Mb) 198 .word 0x0000 | base address=0 199 .word 0x9200 | data read/write 200 .word 0x00C0 | granularity=4096, 386 201 202 idt_48: 203 .word 0 | idt limit=0 204 .word 0,0 | idt base=0L 205 206 gdt_48: 207 .word 0x800 | gdt limit=2048, 256 GDT entries 208 .word 512+gdt,0x9 | gdt base = 0X9xxxx 209 210 .text 211 endtext: 212 .data 213 enddata: 214 .bss 215 endbss: