mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 12:02:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			179 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			179 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| #include <Kernel/Sections.h>
 | |
| 
 | |
| .extern init_ap
 | |
| .type init_ap, @function
 | |
| 
 | |
| /*
 | |
|   The apic_ap_start function will be loaded to P0x00008000 where the APIC
 | |
|   will boot the AP from in real mode. This code also contains space for
 | |
|   special variables that *must* remain here. When initializing the APIC,
 | |
|   the code here gets copied to P0x00008000, the variables in here get
 | |
|   populated and then the the boot of the APs will be triggered. Having
 | |
|   the variables here allows us to access them from real mode. Also, the
 | |
|   code here avoids the need for relocation entries.
 | |
| 
 | |
|   Basically, the variables between apic_ap_start and end_apic_ap_start
 | |
|   *MUST* remain here and cannot be moved into a .bss or any other location.
 | |
| */
 | |
| .global apic_ap_start
 | |
| .type apic_ap_start, @function
 | |
| apic_ap_start:
 | |
| .code16
 | |
|     cli
 | |
|     jmp $0x800, $(1f - apic_ap_start) /* avoid relocation entries */
 | |
| 1:
 | |
|     mov %cs, %ax
 | |
|     mov %ax, %ds
 | |
| 
 | |
|     xor %ax, %ax
 | |
|     mov %ax, %sp
 | |
| 
 | |
|     /* load the first temporary gdt */
 | |
|     lgdt (ap_cpu_gdtr_initial - apic_ap_start)
 | |
| 
 | |
|     /* enable PM */
 | |
|     movl %cr0, %eax
 | |
|     orl $1, %eax
 | |
|     movl %eax, %cr0
 | |
| 
 | |
|     ljmpl $8, $(apic_ap_start32 - apic_ap_start + 0x8000)
 | |
| apic_ap_start32:
 | |
| .code32
 | |
|     mov $0x10, %ax
 | |
|     mov %ax, %ss
 | |
|     mov %ax, %ds
 | |
|     mov %ax, %es
 | |
|     mov %ax, %fs
 | |
|     mov %ax, %gs
 | |
| 
 | |
|     movl $0x8000, %ebp
 | |
| 
 | |
|     /* generate a unique ap cpu id (0 means 1st ap, not bsp!) */
 | |
|     xorl %eax, %eax
 | |
|     incl %eax
 | |
|     lock; xaddl %eax, (ap_cpu_id - apic_ap_start)(%ebp) /* avoid relocation entries */
 | |
|     movl %eax, %esi
 | |
| 
 | |
|     /* find our allocated stack based on the generated id */
 | |
|     movl (ap_cpu_init_stacks - apic_ap_start)(%ebp, %eax, 4), %esp
 | |
| 
 | |
|     /* check if we support NX and enable it if we do */
 | |
|     movl $0x80000001, %eax
 | |
|     cpuid
 | |
|     testl $0x100000, %edx
 | |
|     je (1f - apic_ap_start + 0x8000)
 | |
|     /* turn on IA32_EFER.NXE */
 | |
|     movl $0xc0000080, %ecx
 | |
|     rdmsr
 | |
|     orl $0x800, %eax
 | |
|     wrmsr
 | |
| 1:
 | |
| 
 | |
|     /* load the bsp's cr3 value */
 | |
|     movl (ap_cpu_init_cr3 - apic_ap_start)(%ebp), %eax
 | |
|     movl %eax, %cr3
 | |
| 
 | |
|     /* enable PAE + PSE */
 | |
|     movl %cr4, %eax
 | |
|     orl $0x60, %eax
 | |
|     movl %eax, %cr4
 | |
| 
 | |
|     /* enable PG */
 | |
|     movl %cr0, %eax
 | |
|     orl $0x80000000, %eax
 | |
|     movl %eax, %cr0
 | |
| 
 | |
|     /* load a second temporary gdt that points above 3GB */
 | |
|     lgdt (ap_cpu_gdtr_initial2 - apic_ap_start + 0xc0008000)
 | |
| 
 | |
|     /* jump above 3GB into our identity mapped area now */
 | |
|     ljmp $8, $(apic_ap_start32_2 - apic_ap_start + 0xc0008000)
 | |
| apic_ap_start32_2:
 | |
|     /* flush the TLB */
 | |
|     movl %cr3, %eax
 | |
|     movl %eax, %cr3
 | |
| 
 | |
|     movl $0xc0008000, %ebp
 | |
| 
 | |
|     /* now load the final gdt and idt from the identity mapped area */
 | |
|     movl (ap_cpu_gdtr - apic_ap_start)(%ebp), %eax
 | |
|     lgdt (%eax)
 | |
|     movl (ap_cpu_idtr - apic_ap_start)(%ebp), %eax
 | |
|     lidt (%eax)
 | |
| 
 | |
|     /* set same cr0 and cr4 values as the BSP */
 | |
|     movl (ap_cpu_init_cr0 - apic_ap_start)(%ebp), %eax
 | |
|     movl %eax, %cr0
 | |
|     movl (ap_cpu_init_cr4 - apic_ap_start)(%ebp), %eax
 | |
|     movl %eax, %cr4
 | |
| 
 | |
|     /* push the Processor pointer this CPU is going to use */
 | |
|     movl (ap_cpu_init_processor_info_array - apic_ap_start)(%ebp), %eax
 | |
|     addl kernel_mapping_base, %eax
 | |
|     movl 0(%eax, %esi, 4), %eax
 | |
|     push %eax
 | |
| 
 | |
|     /* push the cpu id, 0 representing the bsp and call into c++ */
 | |
|     incl %esi
 | |
|     push %esi
 | |
| 
 | |
|     xor %ebp, %ebp
 | |
|     cld
 | |
| 
 | |
|     /* We are in identity mapped P0x8000 and the BSP will unload this code
 | |
|        once all APs are initialized, so call init_ap but return to our
 | |
|        infinite loop */
 | |
|     push $loop
 | |
|     ljmp $8, $init_ap
 | |
| 
 | |
| loop:
 | |
|     hlt
 | |
|     jmp loop
 | |
| 
 | |
| .align 4
 | |
| .global apic_ap_start_size
 | |
| apic_ap_start_size:
 | |
|     .2byte end_apic_ap_start - apic_ap_start
 | |
| .align 4
 | |
| ap_cpu_id:
 | |
|     .4byte 0x0
 | |
| ap_cpu_gdt:
 | |
|     /* null */
 | |
|     .8byte 0x0
 | |
|     /* code */
 | |
|     .4byte 0x0000FFFF
 | |
|     .4byte 0x00cf9a00
 | |
|     /* data */
 | |
|     .4byte 0x0000FFFF
 | |
|     .4byte 0x00cf9200
 | |
| ap_cpu_gdt_end:
 | |
| ap_cpu_gdtr_initial:
 | |
|     .2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
 | |
|     .4byte (ap_cpu_gdt - apic_ap_start) + 0x8000
 | |
| ap_cpu_gdtr_initial2:
 | |
|     .2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
 | |
|     .4byte (ap_cpu_gdt - apic_ap_start) + 0xc0008000
 | |
| .global ap_cpu_gdtr
 | |
| ap_cpu_gdtr:
 | |
|     .4byte 0x0 /* will be set at runtime */
 | |
| .global ap_cpu_idtr
 | |
| ap_cpu_idtr:
 | |
|     .4byte 0x0 /* will be set at runtime */
 | |
| .global ap_cpu_init_cr0
 | |
| ap_cpu_init_cr0:
 | |
|     .4byte 0x0 /* will be set at runtime */
 | |
| .global ap_cpu_init_cr3
 | |
| ap_cpu_init_cr3:
 | |
|     .4byte 0x0 /* will be set at runtime */
 | |
| .global ap_cpu_init_cr4
 | |
| ap_cpu_init_cr4:
 | |
|     .4byte 0x0 /* will be set at runtime */
 | |
| .global ap_cpu_init_processor_info_array
 | |
| ap_cpu_init_processor_info_array:
 | |
|     .4byte 0x0 /* will be set at runtime */
 | |
| .global ap_cpu_init_stacks
 | |
| ap_cpu_init_stacks:
 | |
|     /* array of allocated stack pointers */
 | |
|     /* NOTE: ap_cpu_init_stacks must be the last variable before
 | |
|              end_apic_ap_start! */
 | |
| .set end_apic_ap_start, .
 | 
