| #include <arch/mmu.h> |
| #include <ros/memlayout.h> |
| #include <arch/trap.h> |
| |
| #define RELOC(x) ((x) - KERNBASE) |
| #define CPUID_PSE_SUPPORT 0x00000008 |
| |
| .globl smp_entry |
| smp_entry: .code16 |
| cli |
| cld |
| lock incw smp_semaphore - smp_entry + 0x1000 # announce our presence |
| spin_start: # grab lock in real mode |
| movw $1, %ax |
| xchgw %ax, smp_boot_lock - smp_entry + 0x1000 |
| test %ax, %ax |
| jne spin_start |
| |
| # Set up rudimentary segmentation |
| xorw %ax, %ax # Segment number zero |
| movw %ax, %ds # -> Data Segment |
| movw %ax, %es # -> Extra Segment |
| movw %ax, %ss # -> Stack Segment |
| # Would like to patch all of these 0x1000's at trampoline relocation time |
| # There's three of them, so we could patch the trampoline code when we load, |
| # once we're sure the entry code will not change anymore |
| # Note that this GDT is straight through, with no KERNBASE translation |
| lgdt gdtdesc - smp_entry + 0x1000 |
| |
| # Turn on protected mode |
| movl %cr0, %eax |
| orl $CR0_PE, %eax |
| movl %eax, %cr0 |
| ljmp $GD_KT, $(protcseg - smp_entry + 0x1000) |
| |
| protcseg: .code32 |
| # Set up the protected-mode data segment registers |
| movw $GD_KD, %ax # Kernel segment selector |
| movw %ax, %ds # -> DS: Data Segment |
| movw %ax, %es # -> ES: Extra Segment |
| movw %ax, %ss # -> SS: Stack Segment |
| movw %ax, %fs # -> FS |
| movw %ax, %gs # -> GS |
| |
| # Turn on Paging |
| movl RELOC(boot_cr3), %eax |
| movl %eax, %cr3 |
| # Enable PSE, if available |
| movl $1, %eax |
| cpuid |
| test $CPUID_PSE_SUPPORT, %edx |
| jz past_pse |
| movl %cr4, %eax |
| orl $CR4_PSE, %eax |
| movl %eax, %cr4 |
| past_pse: |
| # Turn on PGE, no matter what. Ghetto, but we panic if it's not supported. |
| movl %cr4, %eax |
| orl $CR4_PGE, %eax |
| movl %eax, %cr4 |
| movl %cr0, %eax |
| # These cr0 flags are the same as in pmap.c. Keep them in sync |
| orl $(CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP), %eax |
| andl $(~(CR0_TS|CR0_EM|CR0_CD|CR0_NW)), %eax |
| movl %eax, %cr0 |
| |
| # Reload Segments, using the same gdt_pd as Core 0 |
| lgdt gdt_pd |
| movw $GD_KD, %ax # Kernel segment selector |
| movw %ax, %ds # -> DS: Data Segment |
| movw %ax, %es # -> ES: Extra Segment |
| movw %ax, %ss # -> SS: Stack Segment |
| movw $GD_UD|3, %ax # User segment selector, with RPL=3 |
| movw %ax, %fs # -> FS |
| movw %ax, %gs # -> GS |
| ljmp $GD_KT, $here # jumping to original location of trampoline! |
| here: |
| xorl %eax, %eax |
| lldt %ax |
| incl num_cpus |
| movl (smp_stack_top), %esp |
| movl $0, %ebp # so backtrace works |
| call smp_main |
| movl %eax, %esp # use our new stack, value returned from smp_main |
| # note the next two lines are using the direct mapping from smp_boot() |
| movw $0, smp_boot_lock - smp_entry + 0x1000 # release lock |
| lock decw smp_semaphore - smp_entry + 0x1000 # show we are done |
| sti # so we can get the IPI |
| hlt # wait for the IPI to run smp_pcu_init() |
| call smp_final_core_init |
| call smp_idle # idle loop, will have interrupts turned on |
| # smp_idle should never return |
| spin: |
| jmp spin |
| |
| # Below here is just data, stored with the code text |
| .p2align 2 # force 4 byte alignment |
| gdt: |
| SEG_NULL # null seg |
| SEG(STA_X|STA_R, 0, 0xffffffff) # code seg |
| SEG(STA_W, 0, 0xffffffff) # data seg |
| gdtdesc: |
| .word gdtdesc - gdt - 1 # sizeof(gdt) - 1 |
| .long gdt - smp_entry + 0x1000 # address gdt |
| .p2align 2 # force 4 byte alignment |
| .globl smp_boot_lock |
| smp_boot_lock: # this lock word will be only used from |
| .word 0 # its spot in the trampoline (0x1000) |
| .globl smp_semaphore |
| smp_semaphore: # poor man's polling semaphore |
| .word 0 |
| .globl smp_entry_end |
| smp_entry_end: |