diff options
Diffstat (limited to 'src/boot/head.s')
-rw-r--r-- | src/boot/head.s | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/src/boot/head.s b/src/boot/head.s new file mode 100644 index 0000000..915d66a --- /dev/null +++ b/src/boot/head.s | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * linux/boot/head.s | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * head.s contains the 32-bit startup code. | ||
9 | * | ||
10 | * NOTE!!! Startup happens at absolute address 0x00000000, which is also where | ||
11 | * the page directory will exist. The startup code will be overwritten by | ||
12 | * the page directory. | ||
13 | */ | ||
14 | .text | ||
15 | .globl idt,gdt,pg_dir,tmp_floppy_area | ||
16 | pg_dir: | ||
17 | .globl startup_32 | ||
18 | startup_32: | ||
19 | movl $0x10,%eax | ||
20 | mov %ax,%ds | ||
21 | mov %ax,%es | ||
22 | mov %ax,%fs | ||
23 | mov %ax,%gs | ||
24 | lss stack_start,%esp | ||
25 | call setup_idt | ||
26 | call setup_gdt | ||
27 | movl $0x10,%eax # reload all the segment registers | ||
28 | mov %ax,%ds # after changing gdt. CS was already | ||
29 | mov %ax,%es # reloaded in 'setup_gdt' | ||
30 | mov %ax,%fs | ||
31 | mov %ax,%gs | ||
32 | lss stack_start,%esp | ||
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 | |||
39 | /* | ||
40 | * NOTE! 486 should set bit 16, to check for write-protect in supervisor | ||
41 | * mode. Then it would be unnecessary with the "verify_area()"-calls. | ||
42 | * 486 users probably want to set the NE (#5) bit also, so as to use | ||
43 | * int 16 for math errors. | ||
44 | */ | ||
45 | movl %cr0,%eax # check math chip | ||
46 | andl $0x80000011,%eax # Save PG,PE,ET | ||
47 | /* "orl $0x10020,%eax" here for 486 might be good */ | ||
48 | orl $2,%eax # set MP | ||
49 | movl %eax,%cr0 | ||
50 | call check_x87 | ||
51 | jmp after_page_tables | ||
52 | |||
53 | /* | ||
54 | * We depend on ET to be correct. This checks for 287/387. | ||
55 | */ | ||
56 | check_x87: | ||
57 | fninit | ||
58 | fstsw %ax | ||
59 | cmpb $0,%al | ||
60 | je 1f /* no coprocessor: have to set bits */ | ||
61 | movl %cr0,%eax | ||
62 | xorl $6,%eax /* reset MP, set EM */ | ||
63 | movl %eax,%cr0 | ||
64 | ret | ||
65 | .align 2 | ||
66 | 1: .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ | ||
67 | ret | ||
68 | |||
69 | /* | ||
70 | * setup_idt | ||
71 | * | ||
72 | * sets up a idt with 256 entries pointing to | ||
73 | * ignore_int, interrupt gates. It then loads | ||
74 | * idt. Everything that wants to install itself | ||
75 | * in the idt-table may do so themselves. Interrupts | ||
76 | * are enabled elsewhere, when we can be relatively | ||
77 | * sure everything is ok. This routine will be over- | ||
78 | * written by the page tables. | ||
79 | */ | ||
80 | setup_idt: | ||
81 | lea ignore_int,%edx | ||
82 | movl $0x00080000,%eax | ||
83 | movw %dx,%ax /* selector = 0x0008 = cs */ | ||
84 | movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ | ||
85 | |||
86 | lea idt,%edi | ||
87 | mov $256,%ecx | ||
88 | rp_sidt: | ||
89 | movl %eax,(%edi) | ||
90 | movl %edx,4(%edi) | ||
91 | addl $8,%edi | ||
92 | dec %ecx | ||
93 | jne rp_sidt | ||
94 | lidt idt_descr | ||
95 | ret | ||
96 | |||
97 | /* | ||
98 | * setup_gdt | ||
99 | * | ||
100 | * This routines sets up a new gdt and loads it. | ||
101 | * Only two entries are currently built, the same | ||
102 | * ones that were built in init.s. The routine | ||
103 | * is VERY complicated at two whole lines, so this | ||
104 | * rather long comment is certainly needed :-). | ||
105 | * This routine will beoverwritten by the page tables. | ||
106 | */ | ||
107 | setup_gdt: | ||
108 | lgdt gdt_descr | ||
109 | ret | ||
110 | |||
111 | /* | ||
112 | * I put the kernel page tables right after the page directory, | ||
113 | * using 4 of them to span 16 Mb of physical memory. People with | ||
114 | * more than 16MB will have to expand this. | ||
115 | */ | ||
116 | .org 0x1000 | ||
117 | pg0: | ||
118 | |||
119 | .org 0x2000 | ||
120 | pg1: | ||
121 | |||
122 | .org 0x3000 | ||
123 | pg2: | ||
124 | |||
125 | .org 0x4000 | ||
126 | pg3: | ||
127 | |||
128 | .org 0x5000 | ||
129 | /* | ||
130 | * tmp_floppy_area is used by the floppy-driver when DMA cannot | ||
131 | * reach to a buffer-block. It needs to be aligned, so that it isn't | ||
132 | * on a 64kB border. | ||
133 | */ | ||
134 | tmp_floppy_area: | ||
135 | .fill 1024,1,0 | ||
136 | |||
137 | after_page_tables: | ||
138 | pushl $0 # These are the parameters to main :-) | ||
139 | pushl $0 | ||
140 | pushl $0 | ||
141 | pushl $L6 # return address for main, if it decides to. | ||
142 | pushl $main | ||
143 | jmp setup_paging | ||
144 | L6: | ||
145 | jmp L6 # main should never return here, but | ||
146 | # just in case, we know what happens. | ||
147 | |||
148 | /* This is the default interrupt "handler" :-) */ | ||
149 | int_msg: | ||
150 | .asciz "Unknown interrupt\n\r" | ||
151 | .align 2 | ||
152 | ignore_int: | ||
153 | pushl %eax | ||
154 | pushl %ecx | ||
155 | pushl %edx | ||
156 | push %ds | ||
157 | push %es | ||
158 | push %fs | ||
159 | movl $0x10,%eax | ||
160 | mov %ax,%ds | ||
161 | mov %ax,%es | ||
162 | mov %ax,%fs | ||
163 | pushl $int_msg | ||
164 | call printk | ||
165 | popl %eax | ||
166 | pop %fs | ||
167 | pop %es | ||
168 | pop %ds | ||
169 | popl %edx | ||
170 | popl %ecx | ||
171 | popl %eax | ||
172 | iret | ||
173 | |||
174 | |||
175 | /* | ||
176 | * Setup_paging | ||
177 | * | ||
178 | * This routine sets up paging by setting the page bit | ||
179 | * in cr0. The page tables are set up, identity-mapping | ||
180 | * the first 16MB. The pager assumes that no illegal | ||
181 | * addresses are produced (ie >4Mb on a 4Mb machine). | ||
182 | * | ||
183 | * NOTE! Although all physical memory should be identity | ||
184 | * mapped by this routine, only the kernel page functions | ||
185 | * use the >1Mb addresses directly. All "normal" functions | ||
186 | * use just the lower 1Mb, or the local data space, which | ||
187 | * will be mapped to some other place - mm keeps track of | ||
188 | * that. | ||
189 | * | ||
190 | * For those with more memory than 16 Mb - tough luck. I've | ||
191 | * not got it, why should you :-) The source is here. Change | ||
192 | * it. (Seriously - it shouldn't be too difficult. Mostly | ||
193 | * change some constants etc. I left it at 16Mb, as my machine | ||
194 | * even cannot be extended past that (ok, but it was cheap :-) | ||
195 | * I've tried to show which constants to change by having | ||
196 | * some kind of marker at them (search for "16Mb"), but I | ||
197 | * won't guarantee that's all :-( ) | ||
198 | */ | ||
199 | .align 2 | ||
200 | setup_paging: | ||
201 | movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ | ||
202 | xorl %eax,%eax | ||
203 | xorl %edi,%edi /* pg_dir is at 0x000 */ | ||
204 | cld;rep;stosl | ||
205 | movl $pg0+7,pg_dir /* set present bit/user r/w */ | ||
206 | movl $pg1+7,pg_dir+4 /* --------- " " --------- */ | ||
207 | movl $pg2+7,pg_dir+8 /* --------- " " --------- */ | ||
208 | movl $pg3+7,pg_dir+12 /* --------- " " --------- */ | ||
209 | movl $pg3+4092,%edi | ||
210 | movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */ | ||
211 | std | ||
212 | 1: stosl /* fill pages backwards - more efficient :-) */ | ||
213 | subl $0x1000,%eax | ||
214 | jge 1b | ||
215 | cld | ||
216 | xorl %eax,%eax /* pg_dir is at 0x0000 */ | ||
217 | movl %eax,%cr3 /* cr3 - page directory start */ | ||
218 | movl %cr0,%eax | ||
219 | orl $0x80000000,%eax | ||
220 | movl %eax,%cr0 /* set paging (PG) bit */ | ||
221 | ret /* this also flushes prefetch-queue */ | ||
222 | |||
223 | .align 2 | ||
224 | .word 0 | ||
225 | idt_descr: | ||
226 | .word 256*8-1 # idt contains 256 entries | ||
227 | .long idt | ||
228 | .align 2 | ||
229 | .word 0 | ||
230 | gdt_descr: | ||
231 | .word 256*8-1 # so does gdt (not that that's any | ||
232 | .long gdt # magic number, but it works for me :^) | ||
233 | |||
234 | .align 8 | ||
235 | idt: .fill 256,8,0 # idt is uninitialized | ||
236 | |||
237 | gdt: .quad 0x0000000000000000 /* NULL descriptor */ | ||
238 | .quad 0x00c09a0000000fff /* 16Mb */ | ||
239 | .quad 0x00c0920000000fff /* 16Mb */ | ||
240 | .quad 0x0000000000000000 /* TEMPORARY - don't use */ | ||
241 | .fill 252,8,0 /* space for LDT's and TSS's etc */ | ||