x86_64 boot up
[akaros.git] / kern / arch / x86 / entry64.S
1 /* Copyright (c) 2013 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details. */
4
5 #include <arch/mmu.h>
6 #include <arch/trap.h>
7 #include <arch/x86.h>
8 #include <ros/memlayout.h>
9
10 # Shift Right Logical 
11 #define SRL(val, shamt)         (((val) >> (shamt)) & ~(-1 << (32 - (shamt))))
12
13 #define MULTIBOOT_PAGE_ALIGN  (1<<0)
14 #define MULTIBOOT_MEMORY_INFO (1<<1)
15 #define MULTIBOOT_HEADER_MAGIC (0x1BADB002)
16 #define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
17 #define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS))
18
19 # The kernel bootstrap (this code) is linked and loaded at physical address
20 # 0x00100000 (1MB), which is the start of extended memory.  (See kernel.ld)
21
22 # Flagging boottext to be text.  Check out:
23 # http://sourceware.org/binutils/docs/as/Section.html
24 .section .boottext, "awx"
25
26 .code32
27 .align 4
28 multiboot_header:
29 .long MULTIBOOT_HEADER_MAGIC
30 .long MULTIBOOT_HEADER_FLAGS
31 .long CHECKSUM
32
33 /* Helper: creates count mappings in the PML3 for 1GB jumbo pages for the given
34  * vaddr to paddr range in physical memory.  Then it puts that PML3's addr in
35  * the PML4's appropriate slot.  A few notes:
36  *      - PML3 is responsible for the 9 bits from 30-38, hence the >> 30 and mask
37  *      - PML4 is responsible for the 9 bits from 47-39, hence the >> 39 and mask
38  *      - We use the jumbo PTE_PS flag only on PML3 - can't do it for PML4.
39  *      - PTEs are 8 bytes each, hence the scale = 8 in the indirect addressing
40  *      - The top half of all of PML4's PTEs are set to 0.  This includes the top 20
41  *      bits of the physical address of the page tables - which are 0 in our case.
42  *      - The paddr for the PML3 PTEs is split across two 32-byte halves of the PTE.
43  *      We drop off the lower 30 bits, since we're dealing with 1GB pages.  The 2
44  *      LSBs go at the top of the first half of the PTE, and the remaining 30 are
45  *      the lower 30 of the top half.
46  *      - In general, I use eax as the offset in a PML (the entry is determined by
47  *      the vaddr), edx for the entry I'm writing, and ecx for the value I'm
48  *      writing.  For PML3's mappings, esi tracks which paddr we are on.  Finally,
49  *      I'm using edi for loop control. */
50 #define MAP_GB_PAGES(pml3, vaddr, paddr, count)                                \
51         movl    $(pml3), %edx;                                                     \
52         movl    $(((vaddr) >> 30) & 0x1ff), %eax;                                  \
53         movl    $((paddr) >> 30), %esi;                                            \
54         movl    $(count), %edi;                                                    \
55 1:;                                                                            \
56         movl    %esi, %ecx;                                                        \
57         shll    $30, %ecx;                       /* lower part of PTE ADDR */      \
58         orl             $(PTE_P | PTE_W | PTE_PS), %ecx;                                   \
59         movl    %ecx, (%edx, %eax, 8);                                             \
60         movl    %esi, %ecx;                                                        \
61         shrl    $2, %ecx;                        /* upper part of PTE ADDR */      \
62         movl    %ecx, 4(%edx, %eax, 8);                                            \
63         /* prep for next loop */;                                                  \
64         incl    %eax;                                                              \
65         incl    %esi;                                                              \
66         /* could test eax against count, if we're short on regs */;                \
67         decl    %edi;                                                              \
68         jnz             1b;                                                                \
69         /* now insert the PML3 into pml4 */;                                       \
70         movl    $(((vaddr) >> 39) & 0x1ff), %eax;                                  \
71         movl    $boot_pml4, %edx;                                                  \
72         movl    $(pml3), %ecx;                                                     \
73         orl             $(PTE_P | PTE_W), %ecx;                                            \
74         movl    %ecx, (%edx, %eax, 8);                                             \
75         movl    $0x0, 4(%edx, %eax, 8)
76
77 .globl          _start
78 _start:
79         movw    $0x1234,0x472                   # warm boot
80         # build page table.  need mappings for
81         #       - current code/data at 0x00100000 -> 0x00100000
82         #       - kernel load location: 0xffffffffc0000000 -> 0x0000000000000000
83         #       - kernbase: 0xffff80000000 -> 0x0000000000000000
84         # we'll need one table for the PML4, and three PML3 (PDPE)'s.  1GB will
85         # suffice for lo and hi (til we do the VPT and LAPIC mappings).  For
86         # kernbase, we'll do all 512 PML3 entries (covers 512GB)
87         MAP_GB_PAGES(boot_pml3_lo,       0x0000000000000000, 0x0, 1)
88         MAP_GB_PAGES(boot_pml3_hi,       0xffffffffc0000000, 0x0, 1)
89         MAP_GB_PAGES(boot_pml3_kernbase, 0xffff800000000000, 0x0, 512)
90         # load cr3 - note that in long mode, cr3 is 64 bits wide.  our boot pml4 is
91         # in lower memory, so it'll be fine if the HW 0 extends.
92         movl    $boot_pml4, %eax
93         movl    %eax, %cr3
94         # turn on paging option in cr4.  note we assume PSE support.  if we didn't
95         # have it, then our jumbo page mappings are going to fail.  we also want
96         # global pages (for performance).  PAE is the basics needed for long paging
97         movl    %cr4, %eax
98         orl             $(CR4_PSE | CR4_PGE | CR4_PAE), %eax
99         movl    %eax, %cr4
100         # Turn on the IA32E enabled bit.
101         # rd/wrmsr use ecx for the addr, and eax as the in/out register.
102         movl    $IA32_EFER_MSR, %ecx
103         rdmsr
104         orl             $IA32_EFER_IA32E_EN, %eax
105         wrmsr
106         # Setup cr0.  PE and PG are critical for now.  The others are similar to
107         # what we want in general (-AM with 64 bit, it's useless).
108         movl    %cr0, %eax
109         orl             $(CR0_PE | CR0_PG | CR0_WP | CR0_NE | CR0_MP), %eax  
110         andl    $(~(CR0_AM | CR0_TS | CR0_EM | CR0_CD | CR0_NW)), %eax  
111         movl    %eax, %cr0
112         # load the 64bit GDT and jump to long mode
113         lgdt    gdt64desc
114         ljmp    $0x08, $long_mode
115 .code64
116 long_mode:
117         # paging is on, and our code is still running at 0x00100000.
118         # do some miscellaneous OS setup.  the coreid stuff is so we can call
119         # core_id() before smp_boot. 
120         movabs  $(os_coreid_lookup), %rax
121         movl    $0x0, (%rax)
122         movabs  $(hw_coreid_lookup), %rax
123         movl    $0x0, (%rax)
124         # Clear the frame pointer for proper backtraces
125         movq    $0x0, %rbp
126         movabs  $(bootstacktop), %rsp
127         movabs  $(num_cpus), %rax
128         movl    $0x1, (%rax)
129         # Pass multiboot info to kernel_init (%rdi == arg1)
130         movq    %rbx, %rdi
131         movabs  $(kernel_init), %rax
132         call    *%rax
133         # Should never get here, but in case we do, just spin.
134 spin:   jmp     spin
135
136 .section .bootdata, "aw"
137         .p2align        2               # force 4 byte alignment
138 gdt64:
139         SEG_NULL
140         SEG_CODE_64(0)
141 gdt64desc:
142         .word   (gdt64desc - gdt64 - 1)         # sizeof(gdt64) - 1
143         .long   gdt64           # HW 0-extends this to 64 bit when loading (i think)
144 # boot page tables
145         .align PGSIZE
146 boot_pml4:
147         .space  PGSIZE
148 boot_pml3_lo:
149         .space  PGSIZE
150 boot_pml3_hi:
151         .space  PGSIZE
152 boot_pml3_kernbase:
153         .space  PGSIZE
154
155 # From here down is linked for KERNBASE
156 .data
157         # TODO: do we need these in asm?
158         .globl  vpt
159         .quad   vpt
160         .set    vpt, VPT
161         .globl  vpd
162         .quad   vpd
163         .set    vpd, (VPT + SRL(VPT, 10))
164
165         .p2align        PGSHIFT         # force page alignment
166         .globl          bootstack
167 bootstack:
168         .space          KSTKSIZE
169         .globl          bootstacktop   
170 bootstacktop: