blob: 9cc9ab0f8bdc8ecee655456cd1ba3b3b3add75ce [file] [log] [blame]
Corey Tabaka84697242009-03-26 02:32:01 -04001/*
2 * Copyright (c) 2009 Corey Tabaka
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24/* The magic number for the Multiboot header. */
25#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
26
27/* The flags for the Multiboot header. */
28#if defined(__ELF__) && 0
29#define MULTIBOOT_HEADER_FLAGS 0x00000002
30#else
31#define MULTIBOOT_HEADER_FLAGS 0x00010002
32#endif
33
34/* The magic number passed by a Multiboot-compliant boot loader. */
35#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
36
37#define NUM_INT 0x31
38#define NUM_EXC 0x14
39
40.text
41.global _start
42_start:
43 jmp real_start
44
45.align 4
46
47multiboot_header:
48 /* magic */
49 .int MULTIBOOT_HEADER_MAGIC
50 /* flags */
51 .int MULTIBOOT_HEADER_FLAGS
52 /* checksum */
53 .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
54
55#if !defined(__ELF__) || 1
56 /* header_addr */
57 .int multiboot_header
58 /* load_addr */
59 .int _start
60 /* load_end_addr */
61 .int __bss_start
62 /* bss_end_addr */
63 .int __bss_end
64 /* entry_addr */
65 .int real_start
66#endif
67
68real_start:
69 cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
70 jne 0f
71 movl %ebx, (_multiboot_info)
720:
73 /* setup isr stub descriptors in the idt */
74 movl $_isr, %esi
75 movl $_idt, %edi
76 movl $NUM_INT, %ecx
77
78.Lloop:
79 movl %esi, %ebx
80 movw %bx, (%edi) /* low word in IDT(n).low */
81 shrl $16, %ebx
82 movw %bx, 6(%edi) /* high word in IDT(n).high */
83
84 addl $isr_stub_len, %esi/* index the next ISR stub */
85 addl $8, %edi /* index the next IDT entry */
86
87 loop .Lloop
88
89 lidt _idtr
90 xorl %eax, %eax
91 movl %eax, %cr3
92
93 lgdt _gdtr
94
95 movw $datasel, %ax
96 movw %ax, %ds
97 movw %ax, %es
98 movw %ax, %fs
99 movw %ax, %ss
100 movw %ax, %gs
101 movw %ax, %ss
102
103 movl $_kstack, %esp
104
105 /* zero the bss section */
106 movl $__bss_start, %edi /* starting address of the bss */
107 movl $__bss_end, %ecx /* find the length of the bss in bytes */
108 subl %edi, %ecx
109 shrl $2, %ecx /* convert to 32 bit words, since the bss is aligned anyway */
1102:
111 movl $0, (%edi)
112 addl $4, %edi
113 loop 2b
114
115 /* call the main module */
116 call kmain
117
1180: /* just sit around waiting for interrupts */
119 hlt /* interrupts will unhalt the processor */
120 pause
121 jmp 0b /* so jump back to halt to conserve power */
122
123/* interrupt service routine stubs */
124_isr:
125
126.set i, 0
127.rept NUM_INT
128
129.set isr_stub_start, .
130
131.if i == 8 || (i >= 10 && i <= 14) || i == 17
132 nop /* error code pushed by exception */
133 nop /* 2 nops are the same length as push byte */
134 pushl $i /* interrupt number */
135 jmp interrupt_common
136.else
137 pushl $0 /* fill in error code in iframe */
138 pushl $i /* interrupt number */
139 jmp interrupt_common
140.endif
141
142/* figure out the length of a single isr stub (usually 6 or 9 bytes) */
143.set isr_stub_len, . - isr_stub_start
144
145.set i, i + 1
146.endr
147
148/* annoying, but force AS to use the same (longer) encoding of jmp for all of the stubs */
149.fill 256
150
151interrupt_common:
152 pushl %gs /* save segment registers */
153 pushl %fs
154 pushl %es
155 pushl %ds
156 pusha /* save general purpose registers */
157 movl $datasel, %eax /* put known good value in segment registers */
158 movl %eax, %gs
159 movl %eax, %fs
160 movl %eax, %es
161 movl %eax, %ds
162 movl %esp, %eax /* store stack switch pivot. push esp has errata on some cpus, so use mov/push */
163 pushl %eax
164 movl %esp, %eax /* store pointer to iframe, using same method */
165 pushl %eax
166
167 incl critical_section_count
168
169 call platform_irq
170
171 cmpl $0,%eax
172 je 0f
173 call thread_preempt
174
1750:
176 decl critical_section_count
177
178 popl %eax /* drop pointer to iframe */
179 popl %eax /* restore task_esp, stack switch can occur here if task_esp is modified */
180 movl %eax, %esp
181 popa /* restore general purpose registers */
182 popl %ds /* restore segment registers */
183 popl %es
184 popl %fs
185 popl %gs
186 addl $8, %esp /* drop exception number and error code */
187 iret
188
189.data
190.align 4
191
192/* define the heap end as read-write data containing the default end of the
193 * heap. dynamic memory length discovery can update this value during init.
194 * other archs can define this statically based on the memory layout of the
195 * platform.
196 */
197.global _heap_end
198_heap_end:
199 .int 4096*1024 /* default to 4MB total */
200
201.global _multiboot_info
202_multiboot_info:
203 .int 0
204
205.global _gdtr
206_gdtr:
207 .short _gdt_end - _gdt - 1
208 .int _gdt
209
210.global _gdt
211_gdt:
212 .int 0
213 .int 0
214
215/* ring 0 descriptors */
216.set codesel, . - _gdt
217_code_gde:
218 .short 0xffff /* limit 15:00 */
219 .short 0x0000 /* base 15:00 */
220 .byte 0x00 /* base 23:16 */
221 .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */
222 .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */
223 .byte 0x0 /* base 31:24 */
224
225.set datasel, . - _gdt
226_data_gde:
227 .short 0xffff /* limit 15:00 */
228 .short 0x0000 /* base 15:00 */
229 .byte 0x00 /* base 23:16 */
230 .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */
231 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
232 .byte 0x0 /* base 31:24 */
233
234.set videosel, . - _gdt
235_video_gde:
236 .short 0xffff /* limit 15:00 */
237 .short 0x8000 /* base 15:00 */
238 .byte 0x0b /* base 23:16 */
239 .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */
240 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
241 .byte 0x0 /* base 31:24 */
242
243.if 1
244/* ring 3 descriptors */
245.set user_codesel, . - _gdt
246_user_code_gde:
247 .short 0xffff /* limit 15:00 */
248 .short 0x0000 /* base 15:00 */
249 .byte 0x00 /* base 23:16 */
250 .byte 0b11111010 /* P(1) DPL(11) S(1) 1 C(0) R(1) A(0) */
251 .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */
252 .byte 0x0 /* base 31:24 */
253
254.set user_datasel, . - _gdt
255_user_data_gde:
256 .short 0xffff /* limit 15:00 */
257 .short 0x0000 /* base 15:00 */
258 .byte 0x00 /* base 23:16 */
259 .byte 0b11110010 /* P(1) DPL(11) S(1) 0 E(0) W(1) A(0) */
260 .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
261 .byte 0x0 /* base 31:24 */
262.endif
263
264/* TSS descriptor */
265.if 1
266.set tsssel, . - _gdt
267_tss_gde:
268 .short 0 /* limit 15:00 */
269 .short 0 /* base 15:00 */
270 .byte 0 /* base 23:16 */
271 .byte 0xe9 /* P(1) DPL(11) 0 10 B(0) 1 */
272 .byte 0x00 /* G(0) 0 0 AVL(0) limit 19:16 */
273 .short 0 /* base 31:24 */
274.endif
275
276.global _gdt_end
277_gdt_end:
278
279.global _idtr
280_idtr:
281 .short _idt_end - _idt - 1 /* IDT limit */
282 .int _idt
283
284/* interrupt descriptor table (IDT) */
285.global _idt
286_idt:
287
288.set i, 0
289.rept NUM_INT-1
290 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
291 .short codesel /* selector */
292 .byte 0
293 .byte 0x8e /* present, ring 0, 32-bit interrupt gate */
294 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */
295
296.set i, i + 1
297.endr
298
299/* syscall int (ring 3) */
300_idt30:
301 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
302 .short codesel /* selector */
303 .byte 0
304 .byte 0xee /* present, ring 3, 32-bit interrupt gate */
305 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */
306
307.global _idt_end
308_idt_end:
309
310.bss
311.align 4096
312
313.global _kstack
314.fill 4096
315_kstack: