(c) versus (C)
[helenos.git] / kernel / arch / ia32 / src / boot / boot.S
blob2d2bdd60e3c9b701d69b206f67cd92b65a371bfb
2 # Copyright (c) 2001-2004 Jakub Jermar
3 # Copyright (c) 2005-2006 Martin Decky
4 # All rights reserved.
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
10 # - Redistributions of source code must retain the above copyright
11 #   notice, this list of conditions and the following disclaimer.
12 # - Redistributions in binary form must reproduce the above copyright
13 #   notice, this list of conditions and the following disclaimer in the
14 #   documentation and/or other materials provided with the distribution.
15 # - The name of the author may not be used to endorse or promote products
16 #   derived from this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <arch/boot/boot.h>
31 #include <arch/boot/memmap.h>
32 #include <arch/mm/page.h>
33 #include <arch/pm.h>
35 #define START_STACK (BOOT_OFFSET - BOOT_STACK_SIZE)
37 .section K_TEXT_START, "ax"
39 .code32
40 .align 4
41 .global multiboot_image_start
42 multiboot_header:
43         .long MULTIBOOT_HEADER_MAGIC
44         .long MULTIBOOT_HEADER_FLAGS
45         .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)        # checksum
46         .long multiboot_header
47         .long unmapped_ktext_start
48         .long 0
49         .long 0
50         .long multiboot_image_start
51         
52 multiboot_image_start:
53         movl $START_STACK, %esp                 # initialize stack pointer
54         lgdt KA2PA(bootstrap_gdtr)              # initialize Global Descriptor Table register
56         movw $selector(KDATA_DES), %cx
57         movw %cx, %es
58         movw %cx, %fs
59         movw %cx, %gs
60         movw %cx, %ds                                   # kernel data + stack
61         movw %cx, %ss
62         
63         jmpl $selector(KTEXT_DES), $multiboot_meeting_point
64         multiboot_meeting_point:
65         
66         pushl %ebx                                                      # save parameters from GRUB
67         pushl %eax
68         
69 #ifdef CONFIG_FB
70         mov $vesa_init, %esi
71         mov $VESA_INIT_SEGMENT << 4, %edi
72         mov $e_vesa_init - vesa_init, %ecx
73         cld
74         rep movsb
76         mov $VESA_INIT_SEGMENT << 4, %edi
77         jmpl %edi
78         
79         vesa_meeting_point:
80         
81         mov %esi, KA2PA(vesa_ph_addr)
82         mov %di, KA2PA(vesa_height)
83         shr $16, %edi
84         mov %di, KA2PA(vesa_width)
85         mov %bx, KA2PA(vesa_scanline)
86         shr $16, %ebx
87         mov %bx, KA2PA(vesa_bpp)
88 #endif  
89         
90         call map_kernel                                                 # map kernel and turn paging on
91         
92         popl %eax
93         popl %ebx
94         cmpl $MULTIBOOT_LOADER_MAGIC, %eax                              # compare GRUB signature
95         je valid_boot
96                 
97                 xorl %ecx, %ecx                                                 # no memory size or map available
98                 movl %ecx, e801memorysize
99                 movl %ecx, e820counter
100                 
101                 jmp invalid_boot
102                 
103         valid_boot:
104                 
105                 movl (%ebx), %eax                                               # ebx = physical address of struct multiboot_info
106                 
107                 bt $0, %eax                                                             # mbi->flags[0] (mem_lower, mem_upper valid)
108                 jc mem_valid
109                         
110                         xorl %ecx, %ecx
111                         jmp mem_invalid
112                         
113                 mem_valid:
114                 movl 4(%ebx), %ecx                                              # mbi->mem_lower
115                 addl 8(%ebx), %ecx                                              # mbi->mem_upper
116                 
117                 mem_invalid:
118                 movl %ecx, e801memorysize
119                 
120                 bt $3, %eax                                                             # mbi->flags[3] (mods_count, mods_addr valid)
121                 jc mods_valid
122                         
123                         xorl %ecx, %ecx
124                         movl %ecx, init
125                         jmp mods_end
126                 
127                 mods_valid:
128                 
129                 movl 20(%ebx), %ecx                                             # mbi->mods_count
130                 movl %ecx, init
131                 
132                 cmpl $0, %ecx
133                 je mods_end
134                 
135                 movl 24(%ebx), %esi                                             # mbi->mods_addr
136                 movl $init, %edi
137                 
138                 mods_loop:
139                 
140                         movl 0(%esi), %edx                                      # mods->mod_start
141                         addl $0x80000000, %edx
142                         movl %edx, 4(%edi)
143                         
144                         movl 4(%esi), %edx
145                         subl 0(%esi), %edx                                      # mods->mod_end - mods->mod_start
146                         movl %edx, 8(%edi)
147                         
148                         addl $16, %esi
149                         addl $8 , %edi
150                         
151                         loop mods_loop
152                         
153                 mods_end:
154                 
155                 bt $6, %eax                                                             # mbi->flags[6] (mmap_length, mmap_addr valid)  
156                 jc mmap_valid
157                         
158                         xorl %edx, %edx
159                         jmp mmap_invalid
160                         
161                 mmap_valid:
162                 movl 44(%ebx), %ecx                                             # mbi->mmap_length
163                 movl 48(%ebx), %esi                                             # mbi->mmap_addr
164                 movl $e820table, %edi
165                 xorl %edx, %edx
166                 
167                 mmap_loop:
168                         cmpl $0, %ecx
169                         jle mmap_end
170                         
171                         movl 4(%esi), %eax                                      # mmap->base_addr_low
172                         movl %eax, (%edi)
173                         
174                         movl 8(%esi), %eax                                      # mmap->base_addr_high
175                         movl %eax, 4(%edi)
176                         
177                         movl 12(%esi), %eax                                     # mmap->length_low
178                         movl %eax, 8(%edi)
179                         
180                         movl 16(%esi), %eax                                     # mmap->length_high
181                         movl %eax, 12(%edi)
182                         
183                         movl 20(%esi), %eax                                     # mmap->type
184                         movl %eax, 16(%edi)
185                         
186                         movl (%esi), %eax                                       # mmap->size
187                         addl $0x4, %eax
188                         addl %eax, %esi
189                         subl %eax, %ecx
190                         addl $MEMMAP_E820_RECORD_SIZE, %edi
191                         incl %edx
192                         jmp mmap_loop
193                 
194                 mmap_end:
195                 
196                 mmap_invalid:
197                 movl %edx, e820counter
198                 
199         invalid_boot:
200         
201 #ifdef CONFIG_SMP
202         
203         # copy AP bootstrap routines below 1 MB
204         
205         movl $BOOT_OFFSET, %esi
206         movl $AP_BOOT_OFFSET, %edi
207         movl $_hardcoded_unmapped_size, %ecx
208         cld
209         rep movsb
210         
211 #endif
212         
213         call main_bsp                                                           # never returns
215         cli
216         hlt
218 .global map_kernel
219 map_kernel:
220         #
221         # Here we setup mapping for both the unmapped and mapped sections of the kernel.
222         # For simplicity, we map the entire 4G space.
223         #
224         movl %cr4, %ecx
225         orl $(1<<4), %ecx
226         movl %ecx, %cr4                                                 # turn PSE on
227         
228         movl $(page_directory+0), %esi
229         movl $(page_directory+2048), %edi
230         xorl %ecx, %ecx
231         xorl %ebx, %ebx
233         movl $((1<<7)|(1<<0)), %eax
234         orl %ebx, %eax
235         movl %eax, (%esi,%ecx,4)                                        # mapping 0x00000000+%ecx*4M => 0x00000000+%ecx*4M
236         movl %eax, (%edi,%ecx,4)                                        # mapping 0x80000000+%ecx*4M => 0x00000000+%ecx*4M
237         addl $(4*1024*1024), %ebx
239         incl %ecx
240         cmpl $512, %ecx
241         jl 0b
243         movl %esi, %cr3
244         
245         # turn paging on
246         movl %cr0, %ebx
247         orl $(1<<31), %ebx
248         movl %ebx, %cr0
249         ret
251 #ifdef CONFIG_FB
252 vesa_init:
253         jmp $selector(VESA_INIT_DES), $vesa_init_real - vesa_init
254         
255 .code16
256 vesa_init_real:
257         
258         mov %cr0, %eax
259         and $~1, %eax
260         mov %eax, %cr0
261         
262         jmp $VESA_INIT_SEGMENT, $vesa_init_real2 - vesa_init
263         
264 vesa_init_real2:
265         
266         mov $VESA_INIT_SEGMENT, %bx
267         
268         mov %bx, %es
269         mov %bx, %fs
270         mov %bx, %gs
271         mov %bx, %ds
272         mov %bx, %ss
273         
274         movl %esp, %eax
275         movl $0x0000fffc, %esp
276         movl $0x0000fffc, %ebp
277         pushl %eax
278         
279 #define VESA_INFO_SIZE 1024
281 #define VESA_MODE_LIST_PTR_OFFSET 14
282 #define VESA_MODE_WIDTH_OFFSET 18
283 #define VESA_MODE_HEIGHT_OFFSET 20
284 #define VESA_MODE_BPP_OFFSET 25
285 #define VESA_MODE_SCANLINE_OFFSET 16
286 #define VESA_MODE_PHADDR_OFFSET 40
288 #define VESA_END_OF_MODES 0xffff
290 #define VESA_OK 0x4f
292 #define VESA_GET_INFO 0x4f00
293 #define VESA_GET_MODE_INFO 0x4f01
294 #define VESA_SET_MODE 0x4f02
296 #define CONFIG_VESA_BPP_a 255
298 #if CONFIG_VESA_BPP == 24
299 #undef CONFIG_VESA_BPP_a
300 #define CONFIG_VESA_BPP_a 32
301 #endif
303         mov $VESA_GET_INFO, %ax
304         mov $e_vesa_init - vesa_init, %di
305         push %di
306         int $0x10
307         
308         pop %di
309         cmp $VESA_OK, %al
310         jnz 0f
311         
312         mov 2 + VESA_MODE_LIST_PTR_OFFSET(%di), %si
313         mov %si, %gs
314         mov VESA_MODE_LIST_PTR_OFFSET(%di), %si
315         
316         add $VESA_INFO_SIZE, %di
318 1:# Try next mode
319         mov %gs:(%si), %cx
320         cmp $VESA_END_OF_MODES, %cx
321         jz 0f
322         
323         inc %si
324         inc %si
325         push %cx
326         push %di
327         push %si
328         mov $VESA_GET_MODE_INFO, %ax
329         int $0x10
330         
331         pop %si
332         pop %di
333         pop %cx
334         cmp $VESA_OK, %al
335         jnz 0f
336         
337         mov $CONFIG_VESA_WIDTH, %ax
338         cmp VESA_MODE_WIDTH_OFFSET(%di), %ax
339         jnz 1b
340         
341         mov $CONFIG_VESA_HEIGHT,%ax
342         cmp VESA_MODE_HEIGHT_OFFSET(%di), %ax
343         jnz 1b
344         
345         mov $CONFIG_VESA_BPP, %al
346         cmp VESA_MODE_BPP_OFFSET(%di), %al
347         jz 2f
348         
349         mov $CONFIG_VESA_BPP_a, %al
350         cmp VESA_MODE_BPP_OFFSET(%di), %al
351         jnz 1b
352         
354         
355         mov %cx, %bx
356         or $0xc000, %bx
357         push %di
358         mov $VESA_SET_MODE, %ax
359         int $0x10
360         
361         pop %di
362         cmp $VESA_OK, %al
363         jnz 0f
364         
365         mov VESA_MODE_PHADDR_OFFSET(%di), %esi
366         mov VESA_MODE_WIDTH_OFFSET(%di), %ax
367         shl $16, %eax
368         mov VESA_MODE_HEIGHT_OFFSET(%di), %ax
369         mov VESA_MODE_BPP_OFFSET(%di), %bl
370         xor %bh, %bh
371         shl $16, %ebx
372         mov VESA_MODE_SCANLINE_OFFSET(%di), %bx
373         mov %eax, %edi
374         
375 8:      
376         
377         mov %cr0, %eax
378         or $1, %eax
379         mov %eax, %cr0
380         
381         jmp 9f
383         
384         ljmpl $selector(KTEXT_DES), $(vesa_init_protect - vesa_init + VESA_INIT_SEGMENT << 4)
386 0:# No prefered mode found
387         mov $0x111, %cx
388         push %di
389         push %cx
390         mov $VESA_GET_MODE_INFO, %ax
391         int $0x10
392         
393         pop %cx
394         pop %di
395         cmp $VESA_OK, %al
396         jnz 1f
397         jz 2b                                           # Force relative jump
398         
400         mov $0x0003, %ax
401         int $0x10
402         mov $0xffffffff, %edi           # EGA text mode used, because of problems with VESA
403         xor %ax, %ax
404         jz 8b                                           # Force relative jump
405         
407 .code32
408 vesa_init_protect:
409         popl %esp
411         movw $selector(KDATA_DES), %cx
412         movw %cx, %es
413         movw %cx, %fs
414         movw %cx, %gs
415         movw %cx, %ds                                   # kernel data + stack
416         movw %cx, %ss
417         
418         jmpl $selector(KTEXT_DES), $vesa_meeting_point
420 .align 4
421 e_vesa_init:
422 #endif  
424 .section K_DATA_START, "aw", @progbits
426 .align 4096
427 page_directory:
428         .space 4096, 0