1
2
3
4
5
6
7
8
9
10
11 .text
12 #include <linux/tasks.h>
13 #include <linux/fd.h>
14 #include <linux/linkage.h>
15 #include <asm/segment.h>
16
17 #define CL_MAGIC_ADDR 0x90020
18 #define CL_MAGIC 0xA33F
19 #define CL_BASE_ADDR 0x90000
20 #define CL_OFFSET 0x90022
21
22
23
24
25
26 ENTRY(stext)
27 ENTRY(_stext)
28 startup_32:
29 cld
30 movl $(KERNEL_DS),%eax
31 mov %ax,%ds
32 mov %ax,%es
33 mov %ax,%fs
34 mov %ax,%gs
35 lss stack_start,%esp
36
37
38
39 xorl %eax,%eax
40 movl $ SYMBOL_NAME(_edata),%edi
41 movl $ SYMBOL_NAME(_end),%ecx
42 subl %edi,%ecx
43 cld
44 rep
45 stosb
46
47
48
49
50 call setup_idt
51 xorl %eax,%eax
52 1: incl %eax # check that A20 really IS enabled
53 movl %eax,0x000000 # loop forever if it isn't
54 cmpl %eax,0x100000
55 je 1b
56
57
58
59
60
61 pushl $0
62 popfl
63
64
65
66
67
68 movl $0x90000,%esi
69 movl $ SYMBOL_NAME(empty_zero_page),%edi
70 movl $512,%ecx
71 cld
72 rep
73 movsl
74 xorl %eax,%eax
75 movl $512,%ecx
76 rep
77 stosl
78 cmpw $(CL_MAGIC),CL_MAGIC_ADDR
79 jne 1f
80 movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
81 movzwl CL_OFFSET,%esi
82 addl $(CL_BASE_ADDR),%esi
83 movl $2048,%ecx
84 rep
85 movsb
86 1:
87
88
89
90
91
92
93 movl $3, SYMBOL_NAME(x86)
94 pushfl # push EFLAGS
95 popl %eax # get EFLAGS
96 movl %eax,%ecx # save original EFLAGS
97 xorl $0x40000,%eax # flip AC bit in EFLAGS
98 pushl %eax # copy to EFLAGS
99 popfl # set EFLAGS
100 pushfl # get new EFLAGS
101 popl %eax # put it in eax
102 xorl %ecx,%eax # change in flags
103 andl $0x40000,%eax # check if AC bit changed
104 je is386
105 movl $4,SYMBOL_NAME(x86)
106 movl %ecx,%eax
107 xorl $0x200000,%eax # check ID flag
108 pushl %eax
109 popfl # if we are on a straight 486DX, SX, or
110 pushfl # 487SX we can't change it
111 popl %eax
112 xorl %ecx,%eax
113 andl $0x200000,%eax
114 je is486
115 isnew: pushl %ecx # restore original EFLAGS
116 popfl
117
118 movl $1, %eax # Use the CPUID instruction to
119 .byte 0x0f, 0xa2 # check the processor type
120 movb %al, %cl # save reg for future use
121 andb $0x0f,%ah # mask processor family
122 movb %ah,SYMBOL_NAME(x86)
123 andb $0xf0, %eax # mask model
124 shrb $4, %al
125 movb %al,SYMBOL_NAME(x86_model)
126 andb $0x0f, %cl # mask mask revision
127 movb %cl,SYMBOL_NAME(x86_mask)
128 movl %edx,SYMBOL_NAME(x86_capability)
129
130 xorl %eax, %eax # call CPUID with 0 -> return vendor ID
131 .byte 0x0f, 0xa2 # CPUID
132 movl %ebx,SYMBOL_NAME(x86_vendor_id) # lo 4 chars
133 movl %edx,SYMBOL_NAME(x86_vendor_id)+4 # next 4 chars
134 movl %ecx,SYMBOL_NAME(x86_vendor_id)+8 # last 4 chars
135
136 movl %cr0,%eax # 486+
137 andl $0x80000011,%eax # Save PG,PE,ET
138 orl $0x50022,%eax # set AM, WP, NE and MP
139 jmp 2f
140 is486: pushl %ecx # restore original EFLAGS
141 popfl
142 movl %cr0,%eax # 486
143 andl $0x80000011,%eax # Save PG,PE,ET
144 orl $0x50022,%eax # set AM, WP, NE and MP
145 jmp 2f
146 is386: pushl %ecx # restore original EFLAGS
147 popfl
148 movl %cr0,%eax # 386
149 andl $0x80000011,%eax # Save PG,PE,ET
150 orl $2,%eax # set MP
151 2: movl %eax,%cr0
152 call check_x87
153 call setup_paging
154 lgdt gdt_descr
155 lidt idt_descr
156 ljmp $(KERNEL_CS),$1f
157 1: movl $(KERNEL_DS),%eax # reload all the segment registers
158 mov %ax,%ds # after changing gdt.
159 mov %ax,%es
160 mov %ax,%fs
161 mov %ax,%gs
162 lss stack_start,%esp
163 xorl %eax,%eax
164 lldt %ax
165 pushl %eax # These are the parameters to main :-)
166 pushl %eax
167 pushl %eax
168 cld # gcc2 wants the direction flag cleared at all times
169 call SYMBOL_NAME(start_kernel)
170 L6:
171 jmp L6 # main should never return here, but
172
173
174
175
176
177 check_x87:
178 movb $0,SYMBOL_NAME(hard_math)
179 clts
180 fninit
181 fstsw %ax
182 cmpb $0,%al
183 je 1f
184 movl %cr0,%eax
185 xorl $4,%eax
186 movl %eax,%cr0
187 ret
188 ALIGN
189 1: movb $1,SYMBOL_NAME(hard_math)
190 .byte 0xDB,0xE4
191 ret
192
193
194
195
196
197
198
199
200
201
202
203 setup_idt:
204 lea ignore_int,%edx
205 movl $(KERNEL_CS << 16),%eax
206 movw %dx,%ax
207 movw $0x8E00,%dx
208
209 lea SYMBOL_NAME(idt),%edi
210 mov $256,%ecx
211 rp_sidt:
212 movl %eax,(%edi)
213 movl %edx,4(%edi)
214 addl $8,%edi
215 dec %ecx
216 jne rp_sidt
217 ret
218
219
220
221
222
223
224
225
226
227
228
229
230
231 ALIGN
232 setup_paging:
233 movl $1024*2,%ecx
234 xorl %eax,%eax
235 movl $ SYMBOL_NAME(swapper_pg_dir),%edi
236 cld;rep;stosl
237
238
239 movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)
240
241
242 movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)+3072
243 movl $ SYMBOL_NAME(pg0)+4092,%edi
244 movl $0x03ff007,%eax
245 std
246 1: stosl
247 subl $0x1000,%eax
248 jge 1b
249 cld
250 movl $ SYMBOL_NAME(swapper_pg_dir),%eax
251 movl %eax,%cr3
252 movl %cr0,%eax
253 orl $0x80000000,%eax
254 movl %eax,%cr0
255 ret
256
257
258
259
260
261
262
263
264
265
266
267 .org 0x1000
268 ENTRY(swapper_pg_dir)
269
270
271
272
273 .org 0x2000
274 ENTRY(pg0)
275
276 .org 0x3000
277 ENTRY(empty_bad_page)
278
279 .org 0x4000
280 ENTRY(empty_bad_page_table)
281
282 .org 0x5000
283 ENTRY(empty_zero_page)
284
285 .org 0x6000
286
287 stack_start:
288 .long SYMBOL_NAME(init_user_stack)+4096
289 .long KERNEL_DS
290
291
292 int_msg:
293 .asciz "Unknown interrupt\n"
294 ALIGN
295 ignore_int:
296 cld
297 pushl %eax
298 pushl %ecx
299 pushl %edx
300 push %ds
301 push %es
302 push %fs
303 movl $(KERNEL_DS),%eax
304 mov %ax,%ds
305 mov %ax,%es
306 mov %ax,%fs
307 pushl $int_msg
308 call SYMBOL_NAME(printk)
309 popl %eax
310 pop %fs
311 pop %es
312 pop %ds
313 popl %edx
314 popl %ecx
315 popl %eax
316 iret
317
318
319
320
321 ALIGN
322 .word 0
323 idt_descr:
324 .word 256*8-1 # idt contains 256 entries
325 .long 0xc0000000+SYMBOL_NAME(idt)
326
327 ENTRY(idt)
328 .fill 256,8,0 # idt is uninitialized
329
330 ALIGN
331 .word 0
332 gdt_descr:
333 .word (8+2*NR_TASKS)*8-1
334 .long 0xc0000000+SYMBOL_NAME(gdt)
335
336
337
338
339
340 ENTRY(gdt)
341 .quad 0x0000000000000000
342 .quad 0x0000000000000000
343 .quad 0xc0c39a000000ffff
344 .quad 0xc0c392000000ffff
345 .quad 0x00cbfa000000ffff
346 .quad 0x00cbf2000000ffff
347 .quad 0x0000000000000000
348 .quad 0x0000000000000000
349 .fill 2*NR_TASKS,8,0