Splits x86 into 32 and 64 bit (XCC)
[akaros.git] / kern / arch / x86 / smp_entry64.S
1 #include <arch/mmu.h>
2 #include <ros/memlayout.h>
3 #include <arch/trap.h>
4
5 #define RELOC(x) ((x) - KERNBASE)
6 #define CPUID_PSE_SUPPORT       0x00000008
7
8 .globl                  smp_entry
9 smp_entry:              .code16
10         cli
11         cld
12         lock incw       smp_semaphore - smp_entry + 0x1000  # announce our presence
13 spin_start:                                             # grab lock in real mode
14         movw    $1, %ax
15         xchgw   %ax, smp_boot_lock - smp_entry + 0x1000
16         test    %ax, %ax
17         jne             spin_start
18
19         # Set up rudimentary segmentation
20         xorw    %ax, %ax                        # Segment number zero
21         movw    %ax, %ds                        # -> Data Segment
22         movw    %ax, %es                        # -> Extra Segment
23         movw    %ax, %ss                        # -> Stack Segment
24         # Would like to patch all of these 0x1000's at trampoline relocation time
25         # There's three of them, so we could patch the trampoline code when we load,
26         # once we're sure the entry code will not change anymore
27         # Note that this GDT is straight through, with no KERNBASE translation
28         lgdt    gdtdesc - smp_entry + 0x1000
29
30         # Turn on protected mode
31         movl    %cr0, %eax
32         orl             $CR0_PE, %eax
33         movl    %eax, %cr0
34         ljmp    $GD_KT, $(protcseg - smp_entry + 0x1000)
35         
36 .code32
37 protcseg:
38         # Set up the protected-mode data segment registers
39         movw    $GD_KD, %ax             # Kernel segment selector
40         movw    %ax, %ds                # -> DS: Data Segment
41         movw    %ax, %es                # -> ES: Extra Segment
42         movw    %ax, %ss                # -> SS: Stack Segment
43         movw    %ax, %fs                # -> FS
44         movw    %ax, %gs                # -> GS
45
46         # Turn on Paging
47         # crap, how do we sort out the relocs such that this is reachable from 32
48         # bit code?  need to put these in a magic location?
49         # XXX movl      RELOC(boot_cr3), %eax
50         movl    %eax, %cr3
51         # Enable PSE, if available
52         movl    $1, %eax
53         cpuid
54         test    $CPUID_PSE_SUPPORT, %edx
55         jz              past_pse
56         movl    %cr4, %eax
57         orl             $CR4_PSE, %eax
58         movl    %eax, %cr4
59 past_pse:
60         # Turn on PGE, no matter what.  Ghetto, but we panic if it's not supported.
61         movl    %cr4, %eax
62         orl             $CR4_PGE, %eax
63         movl    %eax, %cr4
64         movl    %cr0, %eax      
65         # These cr0 flags are the same as in pmap.c.  Keep them in sync
66         orl             $(CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP), %eax  
67         andl    $(~(CR0_TS|CR0_EM|CR0_CD|CR0_NW)), %eax  
68         movl    %eax, %cr0
69
70         # Reload Segments, using the same gdt_pd as Core 0
71         # XXX lgdt      gdt_pd
72         movw    $GD_KD, %ax             # Kernel segment selector
73         movw    %ax, %ds                # -> DS: Data Segment
74         movw    %ax, %es                # -> ES: Extra Segment
75         movw    %ax, %ss                # -> SS: Stack Segment
76         movw    $GD_UD|3, %ax   # User segment selector, with RPL=3
77         movw    %ax, %fs                # -> FS
78         movw    %ax, %gs                # -> GS
79         # TODO: this reloc is mucking up.  it assembles for 32 bit okay, but if you asm
80         # for 64 bit, or if you objcopy ther 32 to 64, it can't find 'here'.  tried
81         # other names too.  is it because the linker doesn't know where smp entry
82         # is going to be, or that it later becomes a 64 bit reloc (unlike in
83         # _start, where we know it is linked for low mem).  Subtracting them gives
84         # the linker the ability to do the math now. (don't forget you can't trust
85         # the disassembly when the format doesn't match the code type)
86         # 
87         # we're going to have issues with all of the relocs like that - trying to
88         # find 64 bit addresses in 32 bit code.  for all of the external ones,
89         # we're going to need to either put the memory in here, so we don't need to
90         # reloc, or do it after we turn on 64b mode
91
92
93         # ljmp  $GD_KT, $(here) # jumping to original location of trampoline!
94         ljmp    $GD_KT, $(here - smp_entry + 0x1000)
95 here:
96         xorl    %eax, %eax
97         lldt    %ax
98         # XXX incl      num_cpus
99         # XXX movl      (smp_stack_top), %esp
100         movl    $0, %ebp                # so backtrace works
101         call    smp_main
102         movl    %eax, %esp              # use our new stack, value returned from smp_main
103         # note the next two lines are using the direct mapping from smp_boot()
104         movw    $0, smp_boot_lock - smp_entry + 0x1000  # release lock
105         lock decw       smp_semaphore - smp_entry + 0x1000  # show we are done
106         sti                     # so we can get the IPI
107         hlt                     # wait for the IPI to run smp_pcu_init()
108         call    smp_idle                # idle loop, will have interrupts turned on
109
110         # Below here is just data, stored with the code text
111         .p2align        2                                               # force 4 byte alignment
112 gdt:
113         SEG_NULL                                                        # null seg
114         SEG(STA_X|STA_R, 0, 0xffffffff)         # code seg
115         SEG(STA_W, 0, 0xffffffff)                       # data seg
116 gdtdesc:
117         .word   gdtdesc - gdt - 1                       # sizeof(gdt) - 1
118         .long   gdt - smp_entry + 0x1000        # address gdt
119         .p2align        2                                               # force 4 byte alignment
120 .globl                  smp_boot_lock
121 smp_boot_lock:                                                  # this lock word will be only used from
122         .word   0                                                       # its spot in the trampoline (0x1000)
123 .globl                  smp_semaphore
124 smp_semaphore:                                                  # poor man's polling semaphore
125         .word   0                                                       
126 .globl                  smp_entry_end
127 smp_entry_end: