Added: new boot.S, serial out for Xeon Phi
[barrelfish] / kernel / arch / k1om / boot.S
1 /* * Copyright (c) Intel Corporation (2011).
2 *
3 * Disclaimer: The codes contained in these modules may be specific to the
4 * Intel Software Development Platform codenamed: Knights Ferry, and the
5 * Intel product codenamed: Knights Corner, and are not backward compatible
6 * with other Intel products. Additionally, Intel will NOT support the codes
7 * or instruction set in future products.
8 *
9 * Intel offers no warranty of any kind regarding the code.  This code is
10 * licensed on an "AS IS" basis and Intel is not obligated to provide any support,
11 * assistance, installation, training, or other services of any kind.  Intel is
12 * also not obligated to provide any updates, enhancements or extensions.  Intel
13 * specifically disclaims any warranty of merchantability, non-infringement,
14 * fitness for any particular purpose, and any other warranty.
15 *
16 * Further, Intel disclaims all liability of any kind, including but not
17 * limited to liability for infringement of any proprietary rights, relating
18 * to the use of the code, even if Intel is notified of the possibility of
19 * such liability.  Except as expressly stated in an Intel license agreement
20 * provided with this code and agreed upon with Intel, no license, express
21 * or implied, by estoppel or otherwise, to any intellectual property rights
22 * is granted herein.
23 */
24
25 /*
26  *  linux/boot/head.S
27  *
28  *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
29  */
30
31 /*
32  *  head.S contains the 32-bit startup code.
33  *
34  * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
35  * the page directory will exist. The startup code will be overwritten by
36  * the page directory. [According to comments etc elsewhere on a compressed
37  * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
38  *
39  * Page 0 is deliberately kept safe, since System Management Mode code in
40  * laptops may need to access the BIOS data stored there.  This is also
41  * useful for future device drivers that either access the BIOS via VM86
42  * mode.
43  */
44
45 /*
46  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
47  */
48
49 #include <multiboot.h>
50 #include <target/k1om/offsets_target.h>
51           .code32
52           .text
53
54 #define DECOMPRESS 0
55 #define VERIFYCPU 0
56
57 #define GDT_ENTRY_KERNEL_DS 3
58 #define GDT_ENTRY_KERNEL_CS 2
59 #define __KERNEL_DS (GDT_ENTRY_KERNEL_DS*8)
60 #define __KERNEL_CS (GDT_ENTRY_KERNEL_CS*8)
61 #define BOOT_STACK_SIZE       0x4000
62 #define X86_CR4_PAE 0x00000020 /* enable physical address extensions */
63 #define MSR_EFER              0xc0000080 /* extended feature register */
64 #define _EFER_LME             8  /* Long mode enable */
65 #define X86_CR0_PE  0x00000001 /* Protection Enable */
66 #define X86_CR0_PG  0x80000000 /* Paging */
67
68 #define BP_scratch 484 /* offsetof(struct boot_params, scratch) # */
69 #define BP_loadflags 529 /* offsetof(struct boot_params, hdr.loadflags) # */
70 #define BP_hardware_subarch 572 /* offsetof(struct boot_params, hdr.hardware_subarch)   # */
71 #define BP_version 518 /* offsetof(struct boot_params, hdr.version)     # */
72 #define BP_kernel_alignment 560 /* offsetof(struct boot_params, hdr.kernel_alignment)   # */
73 #define z_extract_offset 0
74 #define LOAD_PHYSICAL_ADDR 0x1000000
75
76
77
78 #ifndef LINKER_SCRIPT
79 #define ALIGN __ALIGN
80 #define ALIGN_STR __ALIGN_STR
81
82 #ifndef ENTRY
83 #define ENTRY(name) \
84   .globl name; \
85   .align 4,0x90; \
86   name:
87 #endif
88 #endif /* LINKER_SCRIPT */
89
90 #ifndef WEAK
91 #define WEAK(name)     \
92           .weak name;            \
93           name:
94 #endif
95
96 #ifndef END
97 #define END(name) \
98   .size name, .-name
99 #endif
100
101 /* If symbol 'name' is treated as a subroutine (gets called, and returns)
102  * then please use ENDPROC to mark 'name' as STT_FUNC for the benefit of
103  * static analysis tools such as stack depth analyzer.
104  */
105 #ifndef ENDPROC
106 #define ENDPROC(name) \
107   .type name, @function; \
108   END(name)
109 #endif
110
111
112           .section  ".head.text","ax"
113           .code32
114 ENTRY(startup_32)
115           cld
116           /*
117            * Test KEEP_SEGMENTS flag to see if the bootloader is asking
118            * us to not reload segments
119            */
120           testb $(1<<6), BP_loadflags(%esi)
121           jnz 1f
122
123           cli
124           movl      $(__KERNEL_DS), %eax
125           movl      %eax, %ds
126           movl      %eax, %es
127           movl      %eax, %ss
128 1:
129
130 /*
131  * Calculate the delta between where we were compiled to run
132  * at and where we were actually loaded at.  This can only be done
133  * with a short local call on x86.  Nothing  else will tell us what
134  * address we are running at.  The reserved chunk of the real-mode
135  * data at 0x1e4 (defined as a scratch field) are used as the stack
136  * for this calculation. Only 4 bytes are needed.
137  */
138           leal      (BP_scratch+4)(%esi), %esp
139           call      1f
140 1:        popl      %ebp
141           subl      $1b, %ebp
142
143 /* setup a stack and make sure cpu supports long mode. */
144           movl      $boot_stack_end, %eax
145           addl      %ebp, %eax
146           movl      %eax, %esp
147 /*
148  * verify_cpu returns 0 if the CPU supports long mode & SSE
149  * ML1OM & MK1OM support long mode, but not SSE
150  */
151 #ifndef VERIFYCPU
152           call      verify_cpu
153           testl     %eax, %eax
154           jnz       no_longmode
155 #endif
156
157 /*
158  * Compute the delta between where we were compiled to run at
159  * and where the code will actually run at.
160  *
161  * %ebp contains the address we are loaded at by the boot loader and %ebx
162  * contains the address where we should move the kernel image temporarily
163  * for safe in-place decompression.
164  */
165           movl      $LOAD_PHYSICAL_ADDR, %ebx
166
167           /* Target address to relocate to for decompression */
168           addl      $z_extract_offset, %ebx
169
170
171 /*
172  * Prepare for entering 64 bit mode
173  */
174
175           /* Load new GDT with the 64bit segments using 32bit descriptor */
176           leal      gdt(%ebp), %eax
177           movl      %eax, gdt+2(%ebp)
178           lgdt      gdt(%ebp)
179
180           /* Enable PAE mode */
181           movl      $(X86_CR4_PAE), %eax
182           movl      %eax, %cr4
183
184  /*
185   * Build early 4G boot pagetable
186   */
187           /* Initialize Page tables to 0 */
188           leal      pgtable(%ebx), %edi
189           xorl      %eax, %eax
190           movl      $((4096*6)/4), %ecx
191           rep       stosl
192
193           /* Build Level 4 */
194           leal      pgtable + 0(%ebx), %edi
195           leal      0x1007 (%edi), %eax
196           movl      %eax, 0(%edi)
197
198           /* Build Level 3 */
199           leal      pgtable + 0x1000(%ebx), %edi
200           leal      0x1007(%edi), %eax
201           movl      $4, %ecx
202 1:        movl      %eax, 0x00(%edi)
203           addl      $0x00001000, %eax
204           addl      $8, %edi
205           decl      %ecx
206           jnz       1b
207
208           /* Build Level 2 */
209           leal      pgtable + 0x2000(%ebx), %edi
210           movl      $0x00000183, %eax
211           movl      $2048, %ecx
212 1:        movl      %eax, 0(%edi)
213           addl      $0x00200000, %eax
214           addl      $8, %edi
215           decl      %ecx
216           jnz       1b
217
218     /* TO SUPPORT "Serial" out */
219
220           /* Build Level 3 */
221           leal      pgtable + 0x1000(%ebx), %edi
222           leal      0x5007(%edi), %eax
223           addl      $256, %edi                    //31st entry
224           movl      %eax, 0x00(%edi)
225
226           /* Build Level 2 */
227           leal      pgtable + 0x6000(%ebx), %edi
228           movl      $0x00000183, %eax
229           movl      $512, %ecx
230 1:        movl      %eax, 0(%edi)
231           addl      $0x00200000, %eax
232           addl      $8, %edi
233           decl      %ecx
234           jnz       1b
235
236           /* Build Level 2 - high part*/
237           leal    pgtable + 0x6000(%ebx), %edi
238           addl      $4, %edi
239           movl    $512, %ecx
240 1:        movl    $0x8, 0(%edi)
241           addl    $8, %edi
242           decl    %ecx
243           jnz     1b
244
245
246           /* Enable the boot page tables */
247           leal      pgtable(%ebx), %eax
248           movl      %eax, %cr3
249
250           /* Enable Long mode in EFER (Extended Feature Enable Register) */
251           movl      $MSR_EFER, %ecx
252           rdmsr
253           btsl      $_EFER_LME, %eax
254           wrmsr
255
256           /*
257            * Setup for the jump to 64bit mode
258            *
259            * When the jump is performend we will be in long mode but
260            * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
261            * (and in turn EFER.LMA = 1).          To jump into 64bit mode we use
262            * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
263            * We place all of the values on our mini stack so lret can
264            * used to perform that far jump.
265            */
266           pushl     $__KERNEL_CS
267           leal      startup_64(%ebp), %eax
268           pushl     %eax
269
270           /* Enter paged protected Mode, activating Long Mode */
271           movl      $(X86_CR0_PG | X86_CR0_PE), %eax /* Enable Paging and Protected mode */
272           movl      %eax, %cr0
273
274           /* Jump from 32bit compatibility mode into 64bit mode. */
275           lret
276 ENDPROC(startup_32)
277
278 no_longmode:
279           /* This isn't an x86-64 CPU so hang */
280 1:
281           hlt
282           jmp     1b
283
284 #if VERIFYCPU
285 #include "../../kernel/verify_cpu.S"
286 #endif
287           /*
288            * Be careful here startup_64 needs to be at a predictable
289            * address so I can export it in an ELF header.  Bootloaders
290            * should look at the ELF header to find this address, as
291            * it may change in the future.
292            */
293           .code64
294           .org 0x400
295 ENTRY(startup_64)
296           /*
297            * We come here either from startup_32 or directly from a
298            * 64bit bootloader.  If we come here from a bootloader we depend on
299            * an identity mapped page table being provied that maps our
300            * entire text+data+bss and hopefully all of memory.
301            */
302
303           /* Setup data segments. */
304           xorl      %eax, %eax
305           movl      %eax, %ds
306           movl      %eax, %es
307           movl      %eax, %ss
308           movl      %eax, %fs
309           movl      %eax, %gs
310           lldt      %ax
311           movl    $0x20, %eax
312           ltr       %ax
313
314 #if 0
315           /*
316            * Compute the decompressed kernel start address.  It is where
317            * we were loaded at aligned to a 2M boundary. %rbp contains the
318            * decompressed kernel start address.
319            *
320            * If it is a relocatable kernel then decompress and run the kernel
321            * from load address aligned to 2MB addr, otherwise decompress and
322            * run the kernel from LOAD_PHYSICAL_ADDR
323            *
324            * We cannot rely on the calculation done in 32-bit mode, since we
325            * may have been invoked via the 64-bit entry point.
326            */
327
328           /* Start with the delta to where the kernel will run at. */
329           movq  $LOAD_PHYSICAL_ADDR, %rbp
330
331           /* Target address to relocate to for decompression */
332           leaq      z_extract_offset(%rbp), %rbx
333
334           /* Set up the stack */
335           leaq      boot_stack_end(%rbx), %rsp
336
337           /* Zero EFLAGS */
338           pushq     $0
339           popfq
340
341
342 /*
343  * Copy the compressed kernel to the end of our buffer
344  * where decompression in place becomes safe.
345  */
346  #if 1
347           pushq     %rsi
348           leaq      (_bss-8)(%rip), %rsi
349           leaq      (_bss-8)(%rbx), %rdi
350           movq      $_bss /* - $startup_32 */, %rcx
351           shrq      $3, %rcx
352           std
353           rep       movsq
354           cld
355           popq      %rsi
356 #endif
357
358 #if 1
359         movabsq $0x08007DAB5C, %r14
360         movl    $0x0A52503E, (%r14)
361         movabsq $0x08007DAB40, %r14
362         movl    $2054847098, (%r14)
363 #endif
364
365
366 /*
367  * Jump to the relocated address.
368  */
369           leaq      relocated(%rbx), %rax
370           jmp       *%rax
371
372           .text
373 relocated:
374
375 #endif
376
377 /*
378  * Clear BSS (stack is currently empty)
379  */
380           xorl      %eax, %eax
381           leaq    _bss(%rip), %rdi
382           leaq    _ebss(%rip), %rcx
383           subq      %rdi, %rcx
384           shrq      $3, %rcx
385           rep       stosq
386
387 /*
388  * Adjust our own GOT
389  */
390           leaq      _got(%rip), %rdx
391           leaq      _egot(%rip), %rcx
392 1:
393           cmpq      %rcx, %rdx
394           jae       2f
395           addq      %rbx, (%rdx)
396           addq      $8, %rdx
397           jmp       1b
398 2:
399
400
401           /* Reset EFLAGS */
402           pushq     $0
403           popf
404
405           lea  (x86_64_kernel_stack + X86_64_KERNEL_STACK_SIZE)(%rip), %rsp
406
407           movl      %eax, %edi          /* Multiboot magic value */
408           movl      %ebx, %esi          /* Pointer to multiboot info struct */
409
410
411 #if 1
412         movabsq $0x08007DAB5C, %r14
413         movl    $0x0A58553E, (%r14)
414         movabsq $0x08007DAB40, %r14
415         movl    $2054847098, (%r14)
416 #endif
417
418
419           call      arch_init
420
421           // jmp       *%rbp
422
423           /* Halt -- this should never be reached */
424 ENTRY(halt)
425           hlt
426           jmp       halt
427
428
429           .data
430 gdt:
431           .word     gdt_end - gdt
432           .long     gdt
433           .word     0
434           .quad     0x0000000000000000  /* NULL descriptor */
435           .quad     0x00af9a000000ffff  /* __KERNEL_CS */
436           .quad     0x00cf92000000ffff  /* __KERNEL_DS */
437           .quad     0x0080890000000000  /* TS descriptor */
438           .quad   0x0000000000000000    /* TS continued */
439 gdt_end:
440
441 /*
442  * Stack and heap for uncompression
443  */
444           .bss
445           .balign 4
446 #if DECOMPRESS
447 boot_heap:
448           .fill BOOT_HEAP_SIZE, 1, 0
449 #endif
450 boot_stack:
451           .fill BOOT_STACK_SIZE, 1, 0
452 boot_stack_end:
453
454 /*
455  * Space for page tables (not in .bss so not zeroed)
456  */
457           .section ".pgtable","a",@nobits
458           .balign 4096
459 pgtable:
460           .fill 7*4096, 1, 0