|  | #include <arch/mmu.h> | 
|  | #include <ros/memlayout.h> | 
|  | #include <arch/trap.h> | 
|  | #include <arch/x86.h> | 
|  |  | 
|  | #define	RELOC(x) ((x) - KERNBASE) | 
|  | #define	CPUID_PSE_SUPPORT	0x00000008 | 
|  |  | 
|  | .globl smp_entry | 
|  | smp_entry: .code16 | 
|  | cli | 
|  | cld | 
|  | # announce our presence | 
|  | lock incw	smp_semaphore - smp_entry + 0x1000 | 
|  | 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 | 
|  | 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) | 
|  | .code32 | 
|  | protcseg: | 
|  | # 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.  We're using the symbol from entry64, which we'll | 
|  | # have no problem linking against (compared to boot_cr3).  this assumes | 
|  | # we use the boot stuff at least through smp_boot. | 
|  | movl	$boot_pml4, %eax | 
|  | movl	%eax, %cr3 | 
|  | # turn on paging option in cr4.  note we assume PSE support.  if we | 
|  | # didn't have it, then our jumbo page mappings are going to fail.  we | 
|  | # also want global pages (for performance).  PAE is the basics needed | 
|  | # for long paging | 
|  | movl	%cr4, %eax | 
|  | orl	$(CR4_PSE | CR4_PGE | CR4_PAE), %eax | 
|  | movl	%eax, %cr4 | 
|  | # Turn on the IA32E enabled bit. | 
|  | # rd/wrmsr use ecx for the addr, and eax as the in/out register. | 
|  | movl	$IA32_EFER_MSR, %ecx | 
|  | rdmsr | 
|  | orl	$IA32_EFER_IA32E_EN, %eax | 
|  | wrmsr | 
|  | # Setup cr0.  PE and PG are critical for now.  The others are similar | 
|  | # to what we want in general (-AM with 64 bit, it's useless). | 
|  | movl	%cr0, %eax | 
|  | orl	$(CR0_PE | CR0_PG | CR0_WP | CR0_NE | CR0_MP), %eax | 
|  | andl	$(~(CR0_AM | CR0_TS | CR0_EM | CR0_CD | CR0_NW)), %eax | 
|  | movl	%eax, %cr0 | 
|  | # load the 64bit GDT and jump to long mode (symbol from entry64) | 
|  | lgdt	gdt64desc | 
|  | # Want to jump to the label long_mode, but we need to relocate to code | 
|  | # reachable by 32 bit code: on our trampoline page. | 
|  | ljmp	$0x08, $(long_mode - smp_entry + 0x1000) | 
|  | .code64 | 
|  | long_mode: | 
|  | # Note: we are still running code on the trampoline | 
|  | # zero the data segments.  Not sure if this is legit or not. | 
|  | xor	%rax, %rax | 
|  | mov	%ax, %ds | 
|  | mov	%ax, %es | 
|  | mov	%ax, %ss | 
|  | mov	%ax, %fs | 
|  | mov	%ax, %gs | 
|  | lldt	%ax | 
|  | incl	x86_num_cores_booted		# an int | 
|  | movq	(smp_stack_top), %rsp | 
|  | movq	$0, %rbp		# so backtrace works | 
|  | # We're on the trampoline, but want to be in the real location of the | 
|  | # smp code (somewhere above KERN_LOAD_ADDR).  This allows us to easily | 
|  | # unmap the boot up memory, which the trampoline is part of. | 
|  | movabs	$(non_trampoline), %rax | 
|  | call	*%rax | 
|  | non_trampoline: | 
|  | call	smp_main | 
|  | # use our new stack, value returned from smp_main | 
|  | movq	%rax, %rsp | 
|  | # note the next two lines are using the direct mapping from smp_boot(). | 
|  | # Remember, the stuff at 0x1000 is a *copy* of the code and data at | 
|  | # KERN_LOAD_ADDR. | 
|  | 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: |