OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [i386/] [kernel/] [head.S] - Blame information for rev 1775

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/arch/i386/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
#include 
13
#include 
14
#include 
15
#include 
16
#include 
17
#include 
18
#include 
19
 
20
 
21
#define CL_MAGIC_ADDR   0x90020
22
#define CL_MAGIC        0xA33F
23
#define CL_BASE_ADDR    0x90000
24
#define CL_OFFSET       0x90022
25
 
26
/*
27
 * swapper_pg_dir is the main page directory, address 0x00001000 (or at
28
 * address 0x00101000 for a compressed boot).
29
 */
30
ENTRY(stext)
31
ENTRY(_stext)
32
startup_32:
33
        cld
34
        movl $(KERNEL_DS),%eax
35
        mov %ax,%ds
36
        mov %ax,%es
37
        mov %ax,%fs
38
        mov %ax,%gs
39
#ifdef __SMP__
40
        orw  %bx,%bx
41
        jz  1f                          /* Initial CPU cleans BSS */
42
/*
43
 *      Set up the stack
44
 */
45
        mov %ax,%ss
46
        xorl %eax,%eax
47
        movw %cx, %ax
48
        movl %eax,%esp
49
        pushl $0
50
        popfl
51
        jmp checkCPUtype
52
1:
53
        lss stack_start,%esp
54
#endif __SMP__
55
/*
56
 * Clear BSS first so that there are no surprises...
57
 */
58
        xorl %eax,%eax
59
        movl $ SYMBOL_NAME(_edata),%edi
60
        movl $ SYMBOL_NAME(_end),%ecx
61
        subl %edi,%ecx
62
        cld
63
        rep
64
        stosb
65
/*
66
 * start system 32-bit setup. We need to re-do some of the things done
67
 * in 16-bit mode for the "real" operations.
68
 */
69
        call setup_idt
70
        xorl %eax,%eax
71
1:      incl %eax               # check that A20 really IS enabled
72
        movl %eax,0x000000      # loop forever if it isn't
73
        cmpl %eax,0x100000
74
        je 1b
75
/*
76
 * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
77
 * confuse the debugger if this code is traced.
78
 * XXX - best to initialize before switching to protected mode.
79
 */
80
        pushl $0
81
        popfl
82
/*
83
 * Copy bootup parameters out of the way. First 2kB of
84
 * _empty_zero_page is for boot parameters, second 2kB
85
 * is for the command line.
86
 */
87
        movl $0x90000,%esi
88
        movl $ SYMBOL_NAME(empty_zero_page),%edi
89
        movl $512,%ecx
90
        cld
91
        rep
92
        movsl
93
        xorl %eax,%eax
94
        movl $512,%ecx
95
        rep
96
        stosl
97
        cmpw $(CL_MAGIC),CL_MAGIC_ADDR
98
        jne 1f
99
        movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
100
        movzwl CL_OFFSET,%esi
101
        addl $(CL_BASE_ADDR),%esi
102
        movl $2048,%ecx
103
        rep
104
        movsb
105
1:
106
#ifdef __SMP__
107
checkCPUtype:
108
#endif
109
 
110
/* check Processor type: 386, 486, 6x86(L) or CPUID capable processor */
111
/*
112
 * XXX - this does a lot of unnecessary setup.  Alignment checks don't
113
 * apply at our cpl of 0 and the stack ought to be aligned already, and
114
 * we don't need to preserve eflags.
115
 */
116
 
117
        movl $3, SYMBOL_NAME(x86)
118
        pushfl                  # push EFLAGS
119
        popl %eax               # get EFLAGS
120
        movl %eax,%ecx          # save original EFLAGS in ecx
121
        xorl $0x40000,%eax      # flip AC bit in EFLAGS
122
        pushl %eax              # copy to EFLAGS
123
        popfl                   # set EFLAGS
124
        pushfl                  # get new EFLAGS
125
        popl %eax               # put it in eax
126
        xorl %ecx,%eax          # change in flags
127
        andl $0x40000,%eax      # check if AC bit changed
128
        je is386
129
        movl $4,SYMBOL_NAME(x86)
130
        movl %ecx,%eax
131
        xorl $0x200000,%eax     # check ID flag
132
        pushl %eax
133
        popfl                   # if we are on a straight 486DX, SX, or
134
        pushfl                  # 487SX we can't change it
135
        popl %eax               # Also if we are on a Cyrix 6x86(L)
136
        xorl %ecx,%eax          # OTOH 6x86MXs and MIIs check OK
137
        andl $0x200000,%eax
138
        je is486x
139
 
140
isnew:  pushl %ecx              # restore original EFLAGS
141
        popfl
142
        incl SYMBOL_NAME(have_cpuid)    # we have CPUID
143
        /*
144
         *      Technically we should use CPUID 0 to see if we have CPUID 1!
145
         */
146
        /* get processor type */
147
        movl $1, %eax           # Use the CPUID instruction to
148
#ifdef GAS_KNOWS_CPUID
149
        cpuid                   # check the processor type
150
#else
151
        .byte 0x0f, 0xa2        # check the processor type
152
#endif
153
        movb %al, %cl           # save reg for future use
154
        andb $0x0f,%ah          # mask processor family
155
        movb %ah,SYMBOL_NAME(x86)
156
        andb $0xf0, %al         # mask model
157
        shrb $4, %al
158
        movb %al,SYMBOL_NAME(x86_model)
159
        andb $0x0f, %cl         # mask mask revision
160
        movb %cl,SYMBOL_NAME(x86_mask)
161
        movl %edx,SYMBOL_NAME(x86_capability)
162
        /* get vendor info */
163
        xorl %eax, %eax                 # call CPUID with 0 -> return vendor ID
164
#ifdef GAS_KNOWS_CPUID
165
        cpuid
166
#else
167
        .byte 0x0f, 0xa2                # CPUID
168
#endif
169
        movl %ebx,SYMBOL_NAME(x86_vendor_id)    # lo 4 chars
170
        movl %edx,SYMBOL_NAME(x86_vendor_id)+4  # next 4 chars
171
        movl %ecx,SYMBOL_NAME(x86_vendor_id)+8  # last 4 chars
172
 
173
        movl %cr0,%eax          # 486+
174
        andl $0x80000011,%eax   # Save PG,PE,ET
175
        orl $0x50022,%eax       # set AM, WP, NE and MP
176
        jmp 2f
177
 
178
/* Now we test if we have a Cyrix 6x86(L). We didn't test before to avoid
179
 * clobbering the new BX chipset used with the Pentium II, which has a register
180
 * at the same addresses as those used to access the Cyrix special configuration
181
 * registers (CCRs).
182
 */
183
        /*
184
         * A Cyrix/IBM 6x86(L) preserves flags after dividing 5 by 2
185
         * (and it _must_ be 5 divided by 2) while other CPUs change
186
         * them in undefined ways. We need to know this since we may
187
         * need to enable the CPUID instruction at least.
188
         * We couldn't use this test before since the PPro and PII behave
189
         * like Cyrix chips in this respect.
190
         */
191
is486x: xor %ax,%ax
192
        sahf
193
        movb $5,%ax
194
        movb $2,%bx
195
        div %bl
196
        lahf
197
        cmpb $2,%ah
198
        jne ncyrix
199
        /*
200
         * N.B. The pattern of accesses to 0x22 and 0x23 is *essential*
201
         *      so do not try to "optimize" it! For the same reason we
202
         *      do all this with interrupts off.
203
         */
204
#define setCx86(reg, val) \
205
        movb reg,%ax;   \
206
        outb %ax,$0x22; \
207
        movb val,%ax;   \
208
        outb %ax,$0x23
209
 
210
#define getCx86(reg) \
211
        movb reg,%ax;   \
212
        outb %ax,$0x22; \
213
        inb $0x23,%ax
214
 
215
        cli
216
        getCx86($0xc3)          # get CCR3
217
        movb %ax,%cx            # Save old value
218
        movb %ax,%bx
219
        andb $0x0f,%bx          # Enable access to all config registers
220
        orb $0x10,%bx           # by setting bit 4
221
        setCx86($0xc3,%bx)
222
 
223
        getCx86($0xfe)          # DIR0 : let's check this is a 6x86(L)
224
        andb $0xf0,%ax          # should be 3xh
225
        cmpb $0x30,%ax          #
226
        jne n6x86
227
 
228
        getCx86($0xe8)          # now we can get CCR4
229
        orb $0x80,%ax           # and set bit 7 (CPUIDEN)
230
        movb %ax,%bx            # to enable CPUID execution
231
        setCx86($0xe8,%bx)
232
 
233
        getCx86($0xe9)          # CCR5 : we reset the SLOP bit
234
        andb $0xfd,%ax          # so that udelay calculation
235
        movb %ax,%bx            # is correct on 6x86(L) CPUs
236
        setCx86($0xe9,%bx)
237
        setCx86($0xc3,%cx)      # Restore old CCR3
238
        sti
239
        jmp isnew               # We enabled CPUID now
240
 
241
n6x86:  setCx86($0xc3,%cx)      # Restore old CCR3
242
        sti
243
ncyrix: pushl %ecx              # restore original EFLAGS
244
        popfl
245
        movl %cr0,%eax          # 486
246
        andl $0x80000011,%eax   # Save PG,PE,ET
247
        orl $0x50022,%eax       # set AM, WP, NE and MP
248
        jmp 2f
249
is386:  pushl %ecx              # restore original EFLAGS
250
        popfl
251
        movl %cr0,%eax          # 386
252
        andl $0x80000011,%eax   # Save PG,PE,ET
253
        orl $2,%eax             # set MP
254
2:      movl %eax,%cr0
255
        call check_x87
256
#ifdef __SMP__
257
        movb ready,%al
258
        orb %al,%al
259
        jz 3f
260
        movl $ SYMBOL_NAME(swapper_pg_dir), %eax
261
        movl %eax, %cr3
262
#ifdef GAS_KNOWS_CR4
263
        movl %cr4,%eax
264
        orl $16,%eax
265
        movl %eax,%cr4
266
#else
267
        .byte 0x0f,0x20,0xe0
268
        orl $16,%eax
269
        .byte 0x0f,0x22,0xe0
270
#endif
271
        movl %cr0, %eax
272
        orl $0x80000000, %eax
273
        movl %eax, %cr0
274
        jmp 4f
275
#endif
276
3:
277
        call setup_paging
278
#ifdef __SMP__
279
        incb ready
280
#endif
281
4:
282
        lgdt gdt_descr
283
        lidt idt_descr
284
        ljmp $(KERNEL_CS),$1f
285
1:      movl $(KERNEL_DS),%eax  # reload all the segment registers
286
        mov %ax,%ds             # after changing gdt.
287
        mov %ax,%es
288
        mov %ax,%fs
289
        mov %ax,%gs
290
#ifdef __SMP__
291
        movl $(KERNEL_DS), %eax
292
        mov  %ax,%ss            # Reload the stack pointer (segment only)
293
#else
294
        lss stack_start,%esp    # Load processor stack
295
#endif
296
        xorl %eax,%eax
297
        lldt %ax
298
        pushl %eax              # These are the parameters to main :-)
299
        pushl %eax
300
        pushl %eax
301
        cld                     # gcc2 wants the direction flag cleared at all times
302
        call SYMBOL_NAME(start_kernel)
303
L6:
304
        jmp L6                  # main should never return here, but
305
                                # just in case, we know what happens.
306
 
307
#ifdef __SMP__
308
ready:  .byte 0
309
#endif
310
 
311
/*
312
 * We depend on ET to be correct. This checks for 287/387.
313
 */
314
check_x87:
315
        movb $0,SYMBOL_NAME(hard_math)
316
        clts
317
        fninit
318
        fstsw %ax
319
        cmpb $0,%al
320
        je 1f
321
        movl %cr0,%eax          /* no coprocessor: have to set bits */
322
        xorl $4,%eax            /* set EM */
323
        movl %eax,%cr0
324
        ret
325
        ALIGN
326
1:      movb $1,SYMBOL_NAME(hard_math)
327
        .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
328
        ret
329
 
330
/*
331
 *  setup_idt
332
 *
333
 *  sets up a idt with 256 entries pointing to
334
 *  ignore_int, interrupt gates. It doesn't actually load
335
 *  idt - that can be done only after paging has been enabled
336
 *  and the kernel moved to PAGE_OFFSET. Interrupts
337
 *  are enabled elsewhere, when we can be relatively
338
 *  sure everything is ok.
339
 */
340
setup_idt:
341
        lea ignore_int,%edx
342
        movl $(KERNEL_CS << 16),%eax
343
        movw %dx,%ax            /* selector = 0x0010 = cs */
344
        movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
345
 
346
        lea SYMBOL_NAME(idt),%edi
347
        mov $256,%ecx
348
rp_sidt:
349
        movl %eax,(%edi)
350
        movl %edx,4(%edi)
351
        addl $8,%edi
352
        dec %ecx
353
        jne rp_sidt
354
        ret
355
 
356
 
357
/*
358
 * Setup_paging
359
 *
360
 * This routine sets up paging by setting the page bit
361
 * in cr0. The page tables are set up, identity-mapping
362
 * the first 4MB.  The rest are initialized later.
363
 *
364
 * (ref: added support for up to 32mb, 17Apr92)  -- Rik Faith
365
 * (ref: update, 25Sept92)  -- croutons@crunchy.uucp
366
 * (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)
367
 */
368
        ALIGN
369
setup_paging:
370
        movl $1024*2,%ecx               /* 2 pages - swapper_pg_dir+1 page table */
371
        xorl %eax,%eax
372
        movl $ SYMBOL_NAME(swapper_pg_dir),%edi /* swapper_pg_dir is at 0x1000 */
373
        cld;rep;stosl
374
/* Identity-map the kernel in low 4MB memory for ease of transition */
375
/* set present bit/user r/w */
376
        movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)
377
/* But the real place is at PAGE_OFFSET */
378
/* set present bit/user r/w */
379
        movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)+__USER_PGD_PTRS*4
380
        movl $ SYMBOL_NAME(pg0)+4092,%edi
381
        movl $0x03ff007,%eax            /*  4Mb - 4096 + 7 (r/w user,p) */
382
        std
383
1:      stosl                   /* fill the page backwards - more efficient :-) */
384
        subl $0x1000,%eax
385
        jge 1b
386
        cld
387
        movl $ SYMBOL_NAME(swapper_pg_dir),%eax
388
        movl %eax,%cr3                  /* cr3 - page directory start */
389
        movl %cr0,%eax
390
        orl $0x80000000,%eax
391
        movl %eax,%cr0          /* set paging (PG) bit */
392
        ret                     /* this also flushes the prefetch-queue */
393
 
394
/*
395
 * page 0 is made non-existent, so that kernel NULL pointer references get
396
 * caught. Thus the swapper page directory has been moved to 0x1000
397
 *
398
 * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte,
399
 * with the introduction of the compressed boot code.  Theoretically,
400
 * the original design of overlaying the startup code with the swapper
401
 * page directory is still possible --- it would reduce the size of the kernel
402
 * by 2-3k.  This would be a good thing to do at some point.....
403
 */
404
.org 0x1000
405
ENTRY(swapper_pg_dir)
406
/*
407
 * The page tables are initialized to only 4MB here - the final page
408
 * tables are set up later depending on memory size.
409
 */
410
.org 0x2000
411
ENTRY(pg0)
412
 
413
.org 0x3000
414
ENTRY(empty_bad_page)
415
 
416
.org 0x4000
417
ENTRY(empty_bad_page_table)
418
 
419
.org 0x5000
420
ENTRY(empty_zero_page)
421
 
422
.org 0x6000
423
 
424
stack_start:
425
        .long SYMBOL_NAME(init_user_stack)+4096
426
        .long KERNEL_DS
427
 
428
/* NOTE: keep the idt short behind the above '.org 0x6000'
429
         It must fit completely within _one_ page */
430
ENTRY(idt)
431
        .fill 256,8,0           # idt is uninitialized
432
 
433
/* This is the default interrupt "handler" :-) */
434
int_msg:
435
        .asciz "Unknown interrupt\n"
436
        ALIGN
437
ignore_int:
438
        cld
439
        pushl %eax
440
        pushl %ecx
441
        pushl %edx
442
        push %ds
443
        push %es
444
        push %fs
445
        movl $(KERNEL_DS),%eax
446
        mov %ax,%ds
447
        mov %ax,%es
448
        mov %ax,%fs
449
        pushl $int_msg
450
        call SYMBOL_NAME(printk)
451
        popl %eax
452
        pop %fs
453
        pop %es
454
        pop %ds
455
        popl %edx
456
        popl %ecx
457
        popl %eax
458
        iret
459
 
460
/*
461
 * The interrupt descriptor table has room for 256 idt's
462
 */
463
        ALIGN
464
.word 0
465
idt_descr:
466
        .word 256*8-1           # idt contains 256 entries
467
        .long __PAGE_OFFSET+SYMBOL_NAME(idt)
468
 
469
        ALIGN
470
.word 0
471
gdt_descr:
472
#ifdef CONFIG_APM
473
        .word (11+2*NR_TASKS)*8-1
474
#else
475
        .word (8+2*NR_TASKS)*8-1
476
#endif
477
        .long __PAGE_OFFSET+SYMBOL_NAME(gdt)
478
 
479
/*
480
 * This gdt setup gives the kernel a 1GB address space at virtual
481
 * address PAGE_OFFSET - space enough for expansion, I hope.
482
 */
483
 
484
#define upper_seg(type,dpl,base,limit) \
485
        ((base) & 0xff000000) | \
486
        (((base) & 0x00ff0000)>>16) | \
487
        (((limit)>>12) & 0xf0000) | \
488
        ((dpl)<<13) | \
489
        (0x00c09000) | \
490
        ((type)<<8)
491
 
492
#define lower_seg(type,dpl,base,limit) \
493
        (((base) & 0x0000ffff)<<16) | \
494
        (((limit)>>12) & 0x0ffff)
495
 
496
#define x86_seg(type,dpl,base,limit) \
497
        .long lower_seg(type,dpl,base,limit); \
498
        .long upper_seg(type,dpl,base,limit)
499
 
500
ENTRY(gdt)
501
        .quad 0x0000000000000000        /* NULL descriptor */
502
        .quad 0x0000000000000000        /* not used */
503
 
504
        /* 0x10 kernel 1GB code at 0xC0000000: */
505
        x86_seg(0xa,0,__PAGE_OFFSET,0xffffffff-__PAGE_OFFSET)
506
 
507
        /* 0x18 kernel 1GB data at 0xC0000000: */
508
        x86_seg(0x2,0,__PAGE_OFFSET,0xffffffff-__PAGE_OFFSET)
509
 
510
        /* 0x23 user 3GB code at 0x00000000: */
511
        x86_seg(0xa,3,0,__PAGE_OFFSET-1)
512
 
513
        /* 0x2b user 3GB data at 0x00000000: */
514
        x86_seg(0x2,3,0,__PAGE_OFFSET-1)
515
 
516
        .quad 0x0000000000000000        /* not used */
517
        .quad 0x0000000000000000        /* not used */
518
        .fill 2*NR_TASKS,8,0            /* space for LDT's and TSS's etc */
519
#ifdef CONFIG_APM
520
        .quad 0x00c09a0000000000        /* APM CS    code */
521
        .quad 0x00809a0000000000        /* APM CS 16 code (16 bit) */
522
        .quad 0x00c0920000000000        /* APM DS    data */
523
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.