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