1 /* 2 * linux/boot/head.S 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 */ 6
7 /* 8 * head.S contains the 32-bit startup code. 9 */ 10
11 .text
12 .globl _idt,_gdt,
13 .globl _swapper_pg_dir,_pg0
14 .globl _empty_bad_page
15 .globl _empty_bad_page_table
16 .globl _empty_zero_page
17 .globl _tmp_floppy_area,_floppy_track_buffer
18
19 #include <linux/tasks.h>
20 #include <linux/segment.h>
21
22 #define CL_MAGIC_ADDR 0x90020
23 #define CL_MAGIC 0xA33F
24 #define CL_BASE_ADDR 0x90000
25 #define CL_OFFSET 0x90022
26
27 /* 28 * swapper_pg_dir is the main page directory, address 0x00001000 29 */ 30 startup_32:
31 cld
32 movl $(KERNEL_DS),%eax
33 mov %ax,%ds
34 mov %ax,%es
35 mov %ax,%fs
36 mov %ax,%gs
37 lss _stack_start,%esp
38 call setup_idt
39 xorl %eax,%eax
40 1: incl %eax # check that A20 really IS enabled
41 movl %eax,0x000000 # loop forever if it isn't
42 cmpl %eax,0x100000
43 je 1b
44 /* 45 * Initialize eflags. Some BIOS's leave bits like NT set. This would 46 * confuse the debugger if this code is traced. 47 * XXX - best to initialize before switching to protected mode. 48 */ 49 pushl $0
50 popfl
51 /* 52 * Copy bootup parameters out of the way. First 2kB of 53 * _empty_zero_page is for boot parameters, second 2kB 54 * is for the command line. 55 */ 56 movl $0x90000,%esi
57 movl $_empty_zero_page,%edi
58 movl $512,%ecx
59 cld
60 rep
61 movsl
62 xorl %eax,%eax
63 movl $512,%ecx
64 rep
65 stosl
66 cmpw $(CL_MAGIC),CL_MAGIC_ADDR
67 jne 1f
68 movl $_empty_zero_page+2048,%edi
69 movzwl CL_OFFSET,%esi
70 addl $(CL_BASE_ADDR),%esi
71 movl $2048,%ecx
72 rep
73 movsb
74 1:
75 /* 76 * Clear BSS 77 */ 78 xorl %eax,%eax
79 movl $__edata,%edi
80 movl $__end,%ecx
81 subl %edi,%ecx
82 cld
83 rep
84 stosb
85 /* check if it is 486 or 386. */ 86 /* 87 * XXX - this does a lot of unnecessary setup. Alignment checks don't 88 * apply at our cpl of 0 and the stack ought to be aligned already, and 89 * we don't need to preserve eflags. 90 */ 91 movl %esp,%edi # save stack pointer
92 andl $0xfffffffc,%esp # align stack to avoid AC fault
93 pushfl # push EFLAGS
94 popl %eax # get EFLAGS
95 movl %eax,%ecx # save original EFLAGS
96 xorl $0x40000,%eax # flip AC bit in EFLAGS
97 pushl %eax # copy to EFLAGS
98 popfl # set EFLAGS
99 pushfl # get new EFLAGS
100 popl %eax # put it in eax
101 xorl %ecx,%eax # change in flags
102 andl $0x40000,%eax # check if AC bit changed
103 jnz 1f # 486
104 pushl %ecx # restore original EFLAGS
105 popfl
106 movl %edi,%esp # restore esp
107 movl %cr0,%eax # 386
108 andl $0x80000011,%eax # Save PG,PE,ET
109 orl $2,%eax # set MP
110 jmp 2f
111 /* 112 * NOTE! 486 should set bit 16, to check for write-protect in supervisor 113 * mode. Then it would be unnecessary with the "verify_area()"-calls. 114 * 486 users probably want to set the NE (#5) bit also, so as to use 115 * int 16 for math errors. 116 * XXX - the above is out of date. We set all the bits, but don't take 117 * advantage of WP (26 Dec 92). 118 */ 119 1: pushl %ecx # restore original EFLAGS
120 popfl
121 movl %edi,%esp # restore esp
122 movl %cr0,%eax # 486
123 andl $0x80000011,%eax # Save PG,PE,ET
124 orl $0x50022,%eax # set AM, WP, NE and MP
125 2: movl %eax,%cr0
126 call check_x87
127 call setup_paging
128 lgdt gdt_descr
129 lidt idt_descr
130 ljmp $(KERNEL_CS),$1f
131 1: movl $(KERNEL_DS),%eax # reload all the segment registers
132 mov %ax,%ds # after changing gdt.
133 mov %ax,%es
134 mov %ax,%fs
135 mov %ax,%gs
136 lss _stack_start,%esp
137 pushl $0 # These are the parameters to main :-)
138 pushl $0
139 pushl $0
140 cld # gcc2 wants the direction flag cleared at all times
141 call _start_kernel
142 L6:
143 jmp L6 # main should never return here, but
144 # just in case, we know what happens. 145
146 /* 147 * We depend on ET to be correct. This checks for 287/387. 148 */ 149 check_x87:
150 movl $0,_hard_math
151 fninit
152 fstsw %ax
153 cmpb $0,%al
154 je 1f
155 movl %cr0,%eax /* no coprocessor: have to set bits */ 156 xorl $4,%eax /* set EM */ 157 movl %eax,%cr0
158 ret
159 .align 2
160 1: movl $1,_hard_math
161 .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ 162 ret
163
164 /* 165 * setup_idt 166 * 167 * sets up a idt with 256 entries pointing to 168 * ignore_int, interrupt gates. It doesn't actually load 169 * idt - that can be done only after paging has been enabled 170 * and the kernel moved to 0xC0000000. Interrupts 171 * are enabled elsewhere, when we can be relatively 172 * sure everything is ok. 173 */ 174 setup_idt:
175 lea ignore_int,%edx
176 movl $(KERNEL_CS << 16),%eax
177 movw %dx,%ax /* selector = 0x0010 = cs */ 178 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ 179
180 lea _idt,%edi
181 mov $256,%ecx
182 rp_sidt:
183 movl %eax,(%edi)
184 movl %edx,4(%edi)
185 addl $8,%edi
186 dec %ecx
187 jne rp_sidt
188 ret
189
190
191 /* 192 * Setup_paging 193 * 194 * This routine sets up paging by setting the page bit 195 * in cr0. The page tables are set up, identity-mapping 196 * the first 4MB. The rest are initialized later. 197 * 198 * (ref: added support for up to 32mb, 17Apr92) -- Rik Faith 199 * (ref: update, 25Sept92) -- croutons@crunchy.uucp 200 * (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit) 201 */ 202 .align 2
203 setup_paging:
204 movl $1024*2,%ecx /* 2 pages - swapper_pg_dir+1 page table */ 205 xorl %eax,%eax
206 movl $_swapper_pg_dir,%edi /* swapper_pg_dir is at 0x1000 */ 207 cld;rep;stosl
208 /* Identity-map the kernel in low 4MB memory for ease of transition */ 209 movl $_pg0+7,_swapper_pg_dir /* set present bit/user r/w */ 210 /* But the real place is at 0xC0000000 */ 211 movl $_pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */ 212 movl $_pg0+4092,%edi
213 movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */ 214 std
215 1: stosl /* fill the page backwards - more efficient :-) */ 216 subl $0x1000,%eax
217 jge 1b
218 cld
219 movl $_swapper_pg_dir,%eax
220 movl %eax,%cr3 /* cr3 - page directory start */ 221 movl %cr0,%eax
222 orl $0x80000000,%eax
223 movl %eax,%cr0 /* set paging (PG) bit */ 224 ret /* this also flushes the prefetch-queue */ 225
226 /* 227 * page 0 is made non-existent, so that kernel NULL pointer references get 228 * caught. Thus the swapper page directory has been moved to 0x1000 229 */ 230 .org 0x1000
231 _swapper_pg_dir:
232 /* 233 * The page tables are initialized to only 4MB here - the final page 234 * tables are set up later depending on memory size. 235 */ 236 .org 0x2000
237 _pg0:
238
239 .org 0x3000
240 _empty_bad_page:
241
242 .org 0x4000
243 _empty_bad_page_table:
244
245 .org 0x5000
246 _empty_zero_page:
247
248 .org 0x6000
249 /* 250 * tmp_floppy_area is used by the floppy-driver when DMA cannot 251 * reach to a buffer-block. It needs to be aligned, so that it isn't 252 * on a 64kB border. 253 */ 254 _tmp_floppy_area:
255 .fill 1024,1,0
256 /* 257 * floppy_track_buffer is used to buffer one track of floppy data: it 258 * has to be separate from the tmp_floppy area, as otherwise a single- 259 * sector read/write can mess it up. It can contain one full track of 260 * data (18*2*512 bytes). 261 */ 262 _floppy_track_buffer:
263 .fill 512*2*18,1,0
264
265 /* This is the default interrupt "handler" :-) */ 266 int_msg:
267 .asciz "Unknown interrupt\n"
268 .align 2
269 ignore_int:
270 cld
271 pushl %eax
272 pushl %ecx
273 pushl %edx
274 push %ds
275 push %es
276 push %fs
277 movl $(KERNEL_DS),%eax
278 mov %ax,%ds
279 mov %ax,%es
280 mov %ax,%fs
281 pushl $int_msg
282 call _printk
283 popl %eax
284 pop %fs
285 pop %es
286 pop %ds
287 popl %edx
288 popl %ecx
289 popl %eax
290 iret
291
292 /* 293 * The interrupt descriptor table has room for 256 idt's 294 */ 295 .align 4
296 .word 0
297 idt_descr:
298 .word 256*8-1 # idt contains 256 entries
299 .long 0xc0000000+_idt
300
301 .align 4
302 _idt:
303 .fill 256,8,0 # idt is uninitialized
304
305 .align 4
306 .word 0
307 gdt_descr:
308 .word (8+2*NR_TASKS)*8-1
309 .long 0xc0000000+_gdt
310
311 /* 312 * This gdt setup gives the kernel a 1GB address space at virtual 313 * address 0xC0000000 - space enough for expansion, I hope. 314 */ 315 .align 4
316 _gdt:
317 .quad 0x0000000000000000 /* NULL descriptor */ 318 .quad 0x0000000000000000 /* not used */ 319 .quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 */ 320 .quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 */ 321 .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */ 322 .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */ 323 .quad 0x0000000000000000 /* not used */ 324 .quad 0x0000000000000000 /* not used */ 325 .fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */