98 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /* See COPYRIGHT for copyright information. */
 | |
| 
 | |
| #include <inc/mmu.h>
 | |
| #include <inc/memlayout.h>
 | |
| 
 | |
| ###################################################################
 | |
| # entry point for APs
 | |
| ###################################################################
 | |
| 
 | |
| # Each non-boot CPU ("AP") is started up in response to a STARTUP
 | |
| # IPI from the boot CPU.  Section B.4.2 of the Multi-Processor
 | |
| # Specification says that the AP will start in real mode with CS:IP
 | |
| # set to XY00:0000, where XY is an 8-bit value sent with the
 | |
| # STARTUP. Thus this code must start at a 4096-byte boundary.
 | |
| #
 | |
| # Because this code sets DS to zero, it must run from an address in
 | |
| # the low 2^16 bytes of physical memory.
 | |
| #
 | |
| # boot_aps() (in init.c) copies this code to MPENTRY_PADDR (which
 | |
| # satisfies the above restrictions).  Then, for each AP, it stores the
 | |
| # address of the pre-allocated per-core stack in mpentry_kstack, sends
 | |
| # the STARTUP IPI, and waits for this code to acknowledge that it has
 | |
| # started (which happens in mp_main in init.c).
 | |
| #
 | |
| # This code is similar to boot/boot.S except that
 | |
| #    - it does not need to enable A20
 | |
| #    - it uses MPBOOTPHYS to calculate absolute addresses of its
 | |
| #      symbols, rather than relying on the linker to fill them
 | |
| 
 | |
| #define RELOC(x) ((x) - KERNBASE)
 | |
| #define MPBOOTPHYS(s) ((s) - mpentry_start + MPENTRY_PADDR)
 | |
| 
 | |
| .set PROT_MODE_CSEG, 0x8	# kernel code segment selector
 | |
| .set PROT_MODE_DSEG, 0x10	# kernel data segment selector
 | |
| 
 | |
| .code16           
 | |
| .globl mpentry_start
 | |
| mpentry_start:
 | |
| 	cli            
 | |
| 
 | |
| 	xorw    %ax, %ax
 | |
| 	movw    %ax, %ds
 | |
| 	movw    %ax, %es
 | |
| 	movw    %ax, %ss
 | |
| 
 | |
| 	lgdt    MPBOOTPHYS(gdtdesc)
 | |
| 	movl    %cr0, %eax
 | |
| 	orl     $CR0_PE, %eax
 | |
| 	movl    %eax, %cr0
 | |
| 
 | |
| 	ljmpl   $(PROT_MODE_CSEG), $(MPBOOTPHYS(start32))
 | |
| 
 | |
| .code32
 | |
| start32:
 | |
| 	movw    $(PROT_MODE_DSEG), %ax
 | |
| 	movw    %ax, %ds
 | |
| 	movw    %ax, %es
 | |
| 	movw    %ax, %ss
 | |
| 	movw    $0, %ax
 | |
| 	movw    %ax, %fs
 | |
| 	movw    %ax, %gs
 | |
| 
 | |
| 	# Set up initial page table. We cannot use kern_pgdir yet because
 | |
| 	# we are still running at a low EIP.
 | |
| 	movl    $(RELOC(entry_pgdir)), %eax
 | |
| 	movl    %eax, %cr3
 | |
| 	# Turn on paging.
 | |
| 	movl    %cr0, %eax
 | |
| 	orl     $(CR0_PE|CR0_PG|CR0_WP), %eax
 | |
| 	movl    %eax, %cr0
 | |
| 
 | |
| 	# Switch to the per-cpu stack allocated in boot_aps()
 | |
| 	movl    mpentry_kstack, %esp
 | |
| 	movl    $0x0, %ebp       # nuke frame pointer
 | |
| 
 | |
| 	# Call mp_main().  (Exercise for the reader: why the indirect call?)
 | |
| 	movl    $mp_main, %eax
 | |
| 	call    *%eax
 | |
| 
 | |
| 	# If mp_main returns (it shouldn't), loop.
 | |
| spin:
 | |
| 	jmp     spin
 | |
| 
 | |
| # Bootstrap GDT
 | |
| .p2align 2					# force 4 byte alignment
 | |
| gdt:
 | |
| 	SEG_NULL				# null seg
 | |
| 	SEG(STA_X|STA_R, 0x0, 0xffffffff)	# code seg
 | |
| 	SEG(STA_W, 0x0, 0xffffffff)		# data seg
 | |
| 
 | |
| gdtdesc:
 | |
| 	.word   0x17				# sizeof(gdt) - 1
 | |
| 	.long   MPBOOTPHYS(gdt)			# address gdt
 | |
| 
 | |
| .globl mpentry_end
 | |
| mpentry_end:
 | |
| 	nop
 |