|
|
1.1 root 1: /*
2: * linux/boot/head.s
3: *
4: * Copyright (C) 1991, 1992 Linus Torvalds
5: */
6:
7: #if (MAX_MEGABYTES != 16) && (MAX_MEGABYTES != 32)
8: #error "MAX_MEGABYTES must be 16 or 32"
9: #endif
10:
11: /*
12: * head.s contains the 32-bit startup code.
13: *
14: * NOTE!!! Startup happens at absolute address 0x00000000, which is also where
15: * the page directory will exist. The startup code will be overwritten by
16: * the page directory.
17: */
18: .text
19: .globl _idt,_gdt,_swapper_pg_dir,_tmp_floppy_area,_floppy_track_buffer
20: /*
21: * swapper_pg_dir is the main page directory, address 0x00000000
22: */
23: _swapper_pg_dir:
24: startup_32:
25: cld
26: movl $0x10,%eax
27: mov %ax,%ds
28: mov %ax,%es
29: mov %ax,%fs
30: mov %ax,%gs
31: lss _stack_start,%esp
32: call setup_idt
33: xorl %eax,%eax
34: 1: incl %eax # check that A20 really IS enabled
35: movl %eax,0x000000 # loop forever if it isn't
36: cmpl %eax,0x100000
37: je 1b
38: /* check if it is 486 or 386. */
39: movl %esp,%edi # save stack pointer
40: andl $0xfffffffc,%esp # align stack to avoid AC fault
41: pushfl # push EFLAGS
42: popl %eax # get EFLAGS
43: movl %eax,%ecx # save original EFLAGS
44: xorl $0x40000,%eax # flip AC bit in EFLAGS
45: pushl %eax # copy to EFLAGS
46: popfl # set EFLAGS
47: pushfl # get new EFLAGS
48: popl %eax # put it in eax
49: xorl %ecx,%eax # check if AC bit is changed. zero is 486.
50: jz 1f # 486
51: pushl %ecx # restore original EFLAGS
52: popfl
53: movl %edi,%esp # restore esp
54: movl %cr0,%eax # 386
55: andl $0x80000011,%eax # Save PG,PE,ET
56: orl $2,%eax # set MP
57: jmp 2f
58: /*
59: * NOTE! 486 should set bit 16, to check for write-protect in supervisor
60: * mode. Then it would be unnecessary with the "verify_area()"-calls.
61: * 486 users probably want to set the NE (#5) bit also, so as to use
62: * int 16 for math errors.
63: */
64: 1: pushl %ecx # restore original EFLAGS
65: popfl
66: movl %edi,%esp # restore esp
67: movl %cr0,%eax # 486
68: andl $0x80000011,%eax # Save PG,PE,ET
69: orl $0x10022,%eax # set NE and MP
70: 2: movl %eax,%cr0
71: call check_x87
72: jmp after_page_tables
73:
74: /*
75: * We depend on ET to be correct. This checks for 287/387.
76: */
77: check_x87:
78: fninit
79: fstsw %ax
80: cmpb $0,%al
81: je 1f
82: movl %cr0,%eax /* no coprocessor: have to set bits */
83: xorl $6,%eax /* reset MP, set EM */
84: movl %eax,%cr0
85: ret
86: .align 2
87: 1: .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
88: ret
89:
90: /*
91: * setup_idt
92: *
93: * sets up a idt with 256 entries pointing to
94: * ignore_int, interrupt gates. It doesn't actually load
95: * idt - that can be done only after paging has been enabled
96: * and the kernel moved to 0xC0000000. Interrupts
97: * are enabled elsewhere, when we can be relatively
98: * sure everything is ok. This routine will be over-
99: * written by the page tables.
100: */
101: setup_idt:
102: lea ignore_int,%edx
103: movl $0x00080000,%eax
104: movw %dx,%ax /* selector = 0x0008 = cs */
105: movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
106:
107: lea _idt,%edi
108: mov $256,%ecx
109: rp_sidt:
110: movl %eax,(%edi)
111: movl %edx,4(%edi)
112: addl $8,%edi
113: dec %ecx
114: jne rp_sidt
115: ret
116:
117: /*
118: * I put the kernel page tables right after the page directory,
119: * using 4 of them to span 16 Mb of physical memory. People with
120: * more than 16MB will have to expand this.
121: * When MAX_MEGABYTES == 32, this is set up for a maximum of 32 MB
122: * (ref: 17Apr92) (redone for 0.97 kernel changes, 1Aug92, ref)
123: */
124: .org 0x1000
125: pg0:
126:
127: .org 0x2000
128: pg1:
129:
130: .org 0x3000
131: pg2:
132:
133: .org 0x4000
134: pg3:
135:
136: .org 0x5000
137: #if MAX_MEGABYTES == 32
138: pg4:
139:
140: .org 0x6000
141: pg5:
142:
143: .org 0x7000
144: pg6:
145:
146: .org 0x8000
147: pg7:
148:
149: .org 0x9000
150: #endif
151: /*
152: * empty_bad_page is a bogus page that will be used when out of memory,
153: * so that a process isn't accidentally killed due to a page fault when
154: * it is running in kernel mode..
155: */
156: .globl _empty_bad_page
157: _empty_bad_page:
158:
159: #if MAX_MEGABYTES == 32
160: .org 0xa000
161: #else
162: .org 0x6000
163: #endif
164: /*
165: * empty_bad_page_table is similar to the above, but is used when the
166: * system needs a bogus page-table
167: */
168: .globl _empty_bad_page_table
169: _empty_bad_page_table:
170:
171: #if MAX_MEGABYTES == 32
172: .org 0xb000
173: #else
174: .org 0x7000
175: #endif
176: /*
177: * tmp_floppy_area is used by the floppy-driver when DMA cannot
178: * reach to a buffer-block. It needs to be aligned, so that it isn't
179: * on a 64kB border.
180: */
181: _tmp_floppy_area:
182: .fill 1024,1,0
183: /*
184: * floppy_track_buffer is used to buffer one track of floppy data: it
185: * has to be separate from the tmp_floppy area, as otherwise a single-
186: * sector read/write can mess it up. It can contain one full track of
187: * data (18*2*512 bytes).
188: */
189: _floppy_track_buffer:
190: .fill 512*2*18,1,0
191:
192: after_page_tables:
193: call setup_paging
194: lgdt gdt_descr
195: lidt idt_descr
196: ljmp $0x08,$1f
197: 1: movl $0x10,%eax # reload all the segment registers
198: mov %ax,%ds # after changing gdt.
199: mov %ax,%es
200: mov %ax,%fs
201: mov %ax,%gs
202: lss _stack_start,%esp
203: pushl $0 # These are the parameters to main :-)
204: pushl $0
205: pushl $0
206: cld # gcc2 wants the direction flag cleared at all times
207: call _start_kernel
208: L6:
209: jmp L6 # main should never return here, but
210: # just in case, we know what happens.
211:
212: /* This is the default interrupt "handler" :-) */
213: int_msg:
214: .asciz "Unknown interrupt\n\r"
215: .align 2
216: ignore_int:
217: cld
218: pushl %eax
219: pushl %ecx
220: pushl %edx
221: push %ds
222: push %es
223: push %fs
224: movl $0x10,%eax
225: mov %ax,%ds
226: mov %ax,%es
227: mov %ax,%fs
228: pushl $int_msg
229: call _printk
230: popl %eax
231: pop %fs
232: pop %es
233: pop %ds
234: popl %edx
235: popl %ecx
236: popl %eax
237: iret
238:
239:
240: /*
241: * Setup_paging
242: *
243: * This routine sets up paging by setting the page bit
244: * in cr0. The page tables are set up, identity-mapping
245: * the first 16MB. The pager assumes that no illegal
246: * addresses are produced (ie >4Mb on a 4Mb machine).
247: *
248: * NOTE! Although all physical memory should be identity
249: * mapped by this routine, only the kernel page functions
250: * use the >1Mb addresses directly. All "normal" functions
251: * use just the lower 1Mb, or the local data space, which
252: * will be mapped to some other place - mm keeps track of
253: * that.
254: *
255: * For those with more memory than 16 Mb - tough luck. I've
256: * not got it, why should you :-) The source is here. Change
257: * it. (Seriously - it shouldn't be too difficult. Mostly
258: * change some constants etc. I left it at 16Mb, as my machine
259: * even cannot be extended past that (ok, but it was cheap :-)
260: * I've tried to show which constants to change by having
261: * some kind of marker at them (search for "16Mb"), but I
262: * won't guarantee that's all :-( )
263: *
264: * (ref: added support for up to 32mb, 17Apr92) -- Rik Faith
265: * (ref: update, 25Sept92) -- [email protected]
266: */
267: .align 2
268: setup_paging:
269: #if MAXMEGABYTES == 32
270: movl $1024*9,%ecx /* 9 pages - swapper_pg_dir+8 page tables */
271: #else
272: movl $1024*5,%ecx /* 5 pages - swapper_pg_dir+4 page tables */
273: #endif
274: xorl %eax,%eax
275: xorl %edi,%edi /* swapper_pg_dir is at 0x000 */
276: cld;rep;stosl
277: /* Identity-map the kernel in low 4MB memory for ease of transition */
278: movl $pg0+7,_swapper_pg_dir /* set present bit/user r/w */
279: /* But the real place is at 0xC0000000 */
280: movl $pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
281: movl $pg1+7,_swapper_pg_dir+3076 /* --------- " " --------- */
282: movl $pg2+7,_swapper_pg_dir+3080 /* --------- " " --------- */
283: movl $pg3+7,_swapper_pg_dir+3084 /* --------- " " --------- */
284: #if MAX_MEGABYTES == 32
285: movl $pg4+7,_swapper_pg_dir+3088 /* --------- " " --------- */
286: movl $pg5+7,_swapper_pg_dir+3092 /* --------- " " --------- */
287: movl $pg6+7,_swapper_pg_dir+3096 /* --------- " " --------- */
288: movl $pg7+7,_swapper_pg_dir+3100 /* --------- " " --------- */
289:
290: movl $pg7+4092,%edi
291: movl $0x1fff007,%eax /* 32Mb - 4096 + 7 (r/w user,p) */
292: #else
293: movl $pg3+4092,%edi
294: movl $0x0fff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */
295: #endif
296: std
297: 1: stosl /* fill pages backwards - more efficient :-) */
298: subl $0x1000,%eax
299: jge 1b
300: cld
301: xorl %eax,%eax /* swapper_pg_dir is at 0x0000 */
302: movl %eax,%cr3 /* cr3 - page directory start */
303: movl %cr0,%eax
304: orl $0x80000000,%eax
305: movl %eax,%cr0 /* set paging (PG) bit */
306: ret /* this also flushes prefetch-queue */
307:
308: /*
309: * The interrupt descriptor table has room for 256 idt's
310: */
311: .align 4
312: .word 0
313: idt_descr:
314: .word 256*8-1 # idt contains 256 entries
315: .long 0xc0000000+_idt
316:
317: .align 4
318: _idt:
319: .fill 256,8,0 # idt is uninitialized
320:
321: /*
322: * The real GDT is also 256 entries long - no real reason
323: */
324: .align 4
325: .word 0
326: gdt_descr:
327: .word 256*8-1
328: .long 0xc0000000+_gdt
329:
330: /*
331: * This gdt setup gives the kernel a 1GB address space at virtual
332: * address 0xC0000000 - space enough for expansion, I hope.
333: */
334: .align 4
335: _gdt:
336: .quad 0x0000000000000000 /* NULL descriptor */
337: .quad 0xc0c39a000000ffff /* 1GB at 0xC0000000 */
338: .quad 0xc0c392000000ffff /* 1GB */
339: .quad 0x0000000000000000 /* TEMPORARY - don't use */
340: .fill 252,8,0 /* space for LDT's and TSS's etc */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.