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