+- add patches.fixes/linux-post-2.6.3-20040220
[linux-flexiantxendom0-3.2.10.git] / arch / i386 / kernel / head.S
1 /*
2  *  linux/arch/i386/kernel/head.S -- the 32-bit startup code.
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  *
6  *  Enhanced CPU detection and feature setting code by Mike Jagdis
7  *  and Martin Mares, November 1997.
8  */
9
10 .text
11 #include <linux/config.h>
12 #include <linux/threads.h>
13 #include <linux/linkage.h>
14 #include <asm/segment.h>
15 #include <asm/page.h>
16 #include <asm/pgtable.h>
17 #include <asm/desc.h>
18 #include <asm/cache.h>
19 #include <asm/thread_info.h>
20
21
22 #define OLD_CL_MAGIC_ADDR       0x90020
23 #define OLD_CL_MAGIC            0xA33F
24 #define OLD_CL_BASE_ADDR        0x90000
25 #define OLD_CL_OFFSET           0x90022
26 #define NEW_CL_POINTER          0x228   /* Relative to real mode data */
27
28 /*
29  * References to members of the new_cpu_data structure.
30  */
31
32 #define CPU_PARAMS      new_cpu_data
33 #define X86             CPU_PARAMS+0
34 #define X86_VENDOR      CPU_PARAMS+1
35 #define X86_MODEL       CPU_PARAMS+2
36 #define X86_MASK        CPU_PARAMS+3
37 #define X86_HARD_MATH   CPU_PARAMS+6
38 #define X86_CPUID       CPU_PARAMS+8
39 #define X86_CAPABILITY  CPU_PARAMS+12
40 #define X86_VENDOR_ID   CPU_PARAMS+36   /* offset dependent on NCAPINTS */
41
42 /*
43  * Initialize page tables
44  */
45 #define INIT_PAGE_TABLES \
46         movl $pg0 - __PAGE_OFFSET, %edi; \
47         /* "007" doesn't mean with license to kill, but PRESENT+RW+USER */ \
48         movl $007, %eax; \
49 2:      stosl; \
50         add $0x1000, %eax; \
51         cmp $empty_zero_page - __PAGE_OFFSET, %edi; \
52         jne 2b;
53
54 /*
55  * swapper_pg_dir is the main page directory, address 0x00101000
56  *
57  * On entry, %esi points to the real-mode code as a 32-bit pointer.
58  */
59 ENTRY(startup_32)
60
61 #ifdef CONFIG_X86_VISWS
62 /*
63  * On SGI Visual Workstations boot CPU starts in protected mode.
64  */
65         orw %bx, %bx
66         jnz 1f
67         INIT_PAGE_TABLES
68         movl $swapper_pg_dir - __PAGE_OFFSET, %eax
69         movl %eax, %cr3
70         lgdt boot_gdt
71 1:
72 #endif
73
74 /*
75  * Set segments to known values
76  */
77         cld
78         movl $(__BOOT_DS),%eax
79         movl %eax,%ds
80         movl %eax,%es
81         movl %eax,%fs
82         movl %eax,%gs
83 #ifdef CONFIG_SMP
84         orw %bx,%bx
85         jz 1f
86
87 /*
88  *      New page tables may be in 4Mbyte page mode and may
89  *      be using the global pages. 
90  *
91  *      NOTE! If we are on a 486 we may have no cr4 at all!
92  *      So we do not try to touch it unless we really have
93  *      some bits in it to set.  This won't work if the BSP
94  *      implements cr4 but this AP does not -- very unlikely
95  *      but be warned!  The same applies to the pse feature
96  *      if not equally supported. --macro
97  *
98  *      NOTE! We have to correct for the fact that we're
99  *      not yet offset PAGE_OFFSET..
100  */
101 #define cr4_bits mmu_cr4_features-__PAGE_OFFSET
102         cmpl $0,cr4_bits
103         je 3f
104         movl %cr4,%eax          # Turn on paging options (PSE,PAE,..)
105         orl cr4_bits,%eax
106         movl %eax,%cr4
107         jmp 3f
108 1:
109 #endif
110         INIT_PAGE_TABLES
111 /*
112  * Enable paging
113  */
114 3:
115         movl $swapper_pg_dir-__PAGE_OFFSET,%eax
116         movl %eax,%cr3          /* set the page table pointer.. */
117         movl %cr0,%eax
118         orl $0x80000000,%eax
119         movl %eax,%cr0          /* ..and set paging (PG) bit */
120         jmp 1f                  /* flush the prefetch-queue */
121 1:
122         movl $1f,%eax
123         jmp *%eax               /* make sure eip is relocated */
124 1:
125         /* Set up the stack pointer */
126         lss stack_start,%esp
127
128 #ifdef CONFIG_SMP
129         orw  %bx,%bx
130         jz  1f                          /* Initial CPU cleans BSS */
131         pushl $0
132         popfl
133         jmp checkCPUtype
134 1:
135 #endif /* CONFIG_SMP */
136
137 /*
138  * Clear BSS first so that there are no surprises...
139  * No need to cld as DF is already clear from cld above...
140  */
141         xorl %eax,%eax
142         movl $__bss_start,%edi
143         movl $__bss_stop,%ecx
144         subl %edi,%ecx
145         rep
146         stosb
147
148 /*
149  * start system 32-bit setup. We need to re-do some of the things done
150  * in 16-bit mode for the "real" operations.
151  */
152         call setup_idt
153 /*
154  * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
155  * confuse the debugger if this code is traced.
156  * XXX - best to initialize before switching to protected mode.
157  */
158         pushl $0
159         popfl
160 /*
161  * Copy bootup parameters out of the way. First 2kB of
162  * _empty_zero_page is for boot parameters, second 2kB
163  * is for the command line.
164  *
165  * Note: %esi still has the pointer to the real-mode data.
166  */
167         movl $empty_zero_page,%edi
168         movl $512,%ecx
169         cld
170         rep
171         movsl
172         xorl %eax,%eax
173         movl $512,%ecx
174         rep
175         stosl
176         movl empty_zero_page+NEW_CL_POINTER,%esi
177         andl %esi,%esi
178         jnz 2f                  # New command line protocol
179         cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
180         jne 1f
181         movzwl OLD_CL_OFFSET,%esi
182         addl $(OLD_CL_BASE_ADDR),%esi
183 2:
184         movl $empty_zero_page+2048,%edi
185         movl $512,%ecx
186         rep
187         movsl
188 1:
189 checkCPUtype:
190
191         movl $-1,X86_CPUID              #  -1 for no CPUID initially
192
193 /* check if it is 486 or 386. */
194 /*
195  * XXX - this does a lot of unnecessary setup.  Alignment checks don't
196  * apply at our cpl of 0 and the stack ought to be aligned already, and
197  * we don't need to preserve eflags.
198  */
199
200         movb $3,X86             # at least 386
201         pushfl                  # push EFLAGS
202         popl %eax               # get EFLAGS
203         movl %eax,%ecx          # save original EFLAGS
204         xorl $0x240000,%eax     # flip AC and ID bits in EFLAGS
205         pushl %eax              # copy to EFLAGS
206         popfl                   # set EFLAGS
207         pushfl                  # get new EFLAGS
208         popl %eax               # put it in eax
209         xorl %ecx,%eax          # change in flags
210         pushl %ecx              # restore original EFLAGS
211         popfl
212         testl $0x40000,%eax     # check if AC bit changed
213         je is386
214
215         movb $4,X86             # at least 486
216         testl $0x200000,%eax    # check if ID bit changed
217         je is486
218
219         /* get vendor info */
220         xorl %eax,%eax                  # call CPUID with 0 -> return vendor ID
221         cpuid
222         movl %eax,X86_CPUID             # save CPUID level
223         movl %ebx,X86_VENDOR_ID         # lo 4 chars
224         movl %edx,X86_VENDOR_ID+4       # next 4 chars
225         movl %ecx,X86_VENDOR_ID+8       # last 4 chars
226
227         orl %eax,%eax                   # do we have processor info as well?
228         je is486
229
230         movl $1,%eax            # Use the CPUID instruction to get CPU type
231         cpuid
232         movb %al,%cl            # save reg for future use
233         andb $0x0f,%ah          # mask processor family
234         movb %ah,X86
235         andb $0xf0,%al          # mask model
236         shrb $4,%al
237         movb %al,X86_MODEL
238         andb $0x0f,%cl          # mask mask revision
239         movb %cl,X86_MASK
240         movl %edx,X86_CAPABILITY
241
242 is486:  movl $0x50022,%ecx      # set AM, WP, NE and MP
243         jmp 2f
244
245 is386:  movl $2,%ecx            # set MP
246 2:      movl %cr0,%eax
247         andl $0x80000011,%eax   # Save PG,PE,ET
248         orl %ecx,%eax
249         movl %eax,%cr0
250
251         call check_x87
252         incb ready
253         lgdt cpu_gdt_descr
254         lidt idt_descr
255         ljmp $(__KERNEL_CS),$1f
256 1:      movl $(__KERNEL_DS),%eax        # reload all the segment registers
257         movl %eax,%ss                   # after changing gdt.
258
259         movl $(__USER_DS),%eax          # DS/ES contains default USER segment
260         movl %eax,%ds
261         movl %eax,%es
262
263         xorl %eax,%eax                  # Clear FS/GS and LDT
264         movl %eax,%fs
265         movl %eax,%gs
266         lldt %ax
267         cld                     # gcc2 wants the direction flag cleared at all times
268 #ifdef CONFIG_SMP
269         movb ready, %cl 
270         cmpb $1,%cl
271         je 1f                   # the first CPU calls start_kernel
272                                 # all other CPUs call initialize_secondary
273         call initialize_secondary
274         jmp L6
275 1:
276 #endif
277         call start_kernel
278 L6:
279         jmp L6                  # main should never return here, but
280                                 # just in case, we know what happens.
281
282 ready:  .byte 0
283
284 /*
285  * We depend on ET to be correct. This checks for 287/387.
286  */
287 check_x87:
288         movb $0,X86_HARD_MATH
289         clts
290         fninit
291         fstsw %ax
292         cmpb $0,%al
293         je 1f
294         movl %cr0,%eax          /* no coprocessor: have to set bits */
295         xorl $4,%eax            /* set EM */
296         movl %eax,%cr0
297         ret
298         ALIGN
299 1:      movb $1,X86_HARD_MATH
300         .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
301         ret
302
303 /*
304  *  setup_idt
305  *
306  *  sets up a idt with 256 entries pointing to
307  *  ignore_int, interrupt gates. It doesn't actually load
308  *  idt - that can be done only after paging has been enabled
309  *  and the kernel moved to PAGE_OFFSET. Interrupts
310  *  are enabled elsewhere, when we can be relatively
311  *  sure everything is ok.
312  */
313 setup_idt:
314         lea ignore_int,%edx
315         movl $(__KERNEL_CS << 16),%eax
316         movw %dx,%ax            /* selector = 0x0010 = cs */
317         movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
318
319         lea idt_table,%edi
320         mov $256,%ecx
321 rp_sidt:
322         movl %eax,(%edi)
323         movl %edx,4(%edi)
324         addl $8,%edi
325         dec %ecx
326         jne rp_sidt
327         ret
328
329 ENTRY(stack_start)
330         .long init_thread_union+THREAD_SIZE
331         .long __BOOT_DS
332
333 /* This is the default interrupt "handler" :-) */
334 int_msg:
335         .asciz "Unknown interrupt\n"
336         ALIGN
337 ignore_int:
338         cld
339         pushl %eax
340         pushl %ecx
341         pushl %edx
342         pushl %es
343         pushl %ds
344         movl $(__KERNEL_DS),%eax
345         movl %eax,%ds
346         movl %eax,%es
347         pushl $int_msg
348         call printk
349         popl %eax
350         popl %ds
351         popl %es
352         popl %edx
353         popl %ecx
354         popl %eax
355         iret
356
357 /*
358  * The IDT and GDT 'descriptors' are a strange 48-bit object
359  * only used by the lidt and lgdt instructions. They are not
360  * like usual segment descriptors - they consist of a 16-bit
361  * segment size, and 32-bit linear address value:
362  */
363
364 .globl idt_descr
365 .globl cpu_gdt_descr
366
367         ALIGN
368         .word 0                         # 32-bit align idt_desc.address
369 idt_descr:
370         .word IDT_ENTRIES*8-1           # idt contains 256 entries
371         .long idt_table
372
373 # boot GDT descriptor (later on used by CPU#0):
374         .word 0                         # 32 bit align gdt_desc.address
375 cpu_gdt_descr:
376         .word GDT_ENTRIES*8-1
377         .long cpu_gdt_table
378
379         .fill NR_CPUS-1,8,0             # space for the other GDT descriptors
380
381 /*
382  * This is initialized to create an identity-mapping at 0-8M (for bootup
383  * purposes) and another mapping of the 0-8M area at virtual address
384  * PAGE_OFFSET.
385  */
386 .org 0x1000
387 ENTRY(swapper_pg_dir)
388         .long 0x00102007
389         .long 0x00103007
390         .fill BOOT_USER_PGD_PTRS-2,4,0
391         /* default: 766 entries */
392         .long 0x00102007
393         .long 0x00103007
394         /* default: 254 entries */
395         .fill BOOT_KERNEL_PGD_PTRS-2,4,0
396
397 /*
398  * The page tables are initialized to only 8MB here - the final page
399  * tables are set up later depending on memory size.
400  */
401 .org 0x2000
402 ENTRY(pg0)
403
404 .org 0x3000
405 ENTRY(pg1)
406
407 /*
408  * empty_zero_page must immediately follow the page tables ! (The
409  * initialization loop counts until empty_zero_page)
410  */
411
412 .org 0x4000
413 ENTRY(empty_zero_page)
414
415 .org 0x5000
416
417 /*
418  * Real beginning of normal "text" segment
419  */
420 ENTRY(stext)
421 ENTRY(_stext)
422
423 /*
424  * This starts the data section. Note that the above is all
425  * in the text section because it has alignment requirements
426  * that we cannot fulfill any other way.
427  */
428 .data
429
430 /*
431  * The Global Descriptor Table contains 28 quadwords, per-CPU.
432  */
433 #if defined(CONFIG_SMP) || defined(CONFIG_X86_VISWS)
434 /*
435  * The boot_gdt_table must mirror the equivalent in setup.S and is
436  * used only by the trampoline for booting other CPUs
437  */
438         .align L1_CACHE_BYTES
439 ENTRY(boot_gdt_table)
440         .fill GDT_ENTRY_BOOT_CS,8,0
441         .quad 0x00cf9a000000ffff        /* kernel 4GB code at 0x00000000 */
442         .quad 0x00cf92000000ffff        /* kernel 4GB data at 0x00000000 */
443 #endif
444         .align L1_CACHE_BYTES
445 ENTRY(cpu_gdt_table)
446         .quad 0x0000000000000000        /* NULL descriptor */
447         .quad 0x0000000000000000        /* 0x0b reserved */
448         .quad 0x0000000000000000        /* 0x13 reserved */
449         .quad 0x0000000000000000        /* 0x1b reserved */
450         .quad 0x0000000000000000        /* 0x20 unused */
451         .quad 0x0000000000000000        /* 0x28 unused */
452         .quad 0x0000000000000000        /* 0x33 TLS entry 1 */
453         .quad 0x0000000000000000        /* 0x3b TLS entry 2 */
454         .quad 0x0000000000000000        /* 0x43 TLS entry 3 */
455         .quad 0x0000000000000000        /* 0x4b reserved */
456         .quad 0x0000000000000000        /* 0x53 reserved */
457         .quad 0x0000000000000000        /* 0x5b reserved */
458
459         .quad 0x00cf9a000000ffff        /* 0x60 kernel 4GB code at 0x00000000 */
460         .quad 0x00cf92000000ffff        /* 0x68 kernel 4GB data at 0x00000000 */
461         .quad 0x00cffa000000ffff        /* 0x73 user 4GB code at 0x00000000 */
462         .quad 0x00cff2000000ffff        /* 0x7b user 4GB data at 0x00000000 */
463
464         .quad 0x0000000000000000        /* 0x80 TSS descriptor */
465         .quad 0x0000000000000000        /* 0x88 LDT descriptor */
466
467         /* Segments used for calling PnP BIOS */
468         .quad 0x00c09a0000000000        /* 0x90 32-bit code */
469         .quad 0x00809a0000000000        /* 0x98 16-bit code */
470         .quad 0x0080920000000000        /* 0xa0 16-bit data */
471         .quad 0x0080920000000000        /* 0xa8 16-bit data */
472         .quad 0x0080920000000000        /* 0xb0 16-bit data */
473         /*
474          * The APM segments have byte granularity and their bases
475          * and limits are set at run time.
476          */
477         .quad 0x00409a0000000000        /* 0xb8 APM CS    code */
478         .quad 0x00009a0000000000        /* 0xc0 APM CS 16 code (16 bit) */
479         .quad 0x0040920000000000        /* 0xc8 APM DS    data */
480
481         .quad 0x0000000000000000        /* 0xd0 - unused */
482         .quad 0x0000000000000000        /* 0xd8 - unused */
483         .quad 0x0000000000000000        /* 0xe0 - unused */
484         .quad 0x0000000000000000        /* 0xe8 - unused */
485         .quad 0x0000000000000000        /* 0xf0 - unused */
486         .quad 0x0000000000000000        /* 0xf8 - GDT entry 31: double-fault TSS */
487
488 #ifdef CONFIG_SMP
489         .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */
490 #endif
491