jehanne/sys/src/kern/amd64/l64sipi.S

212 lines
5.1 KiB
ArmAsm
Raw Normal View History

/*
* Start-up request IPI handler.
*
* This code is executed on an application processor in response to receiving
* a Start-up IPI (SIPI) from another processor.
* This must be placed on a 4KiB boundary
* somewhere in the 1st MiB of conventional memory. However,
* due to some shortcuts below it's restricted further to within the 1st 64KiB.
* The AP starts in real-mode, with
* CS selector set to the startup memory address/16;
* CS base set to startup memory address;
* CS limit set to 64KiB;
* CPL and IP set to 0.
* Parameters are passed to this code via a vector in low memory
* indexed by the APIC number of the processor. The layout, size,
* and location have to be kept in sync with the setup in sipi.s.
*/
#include "mem.h"
#include "amd64.h"
#ifndef __ASSEMBLER__
#define __ASSEMBLER__
#endif
2017-01-10 01:37:55 +01:00
.section .text
/*
* Real mode. Welcome to 1978.
* Load a basic GDT, turn on protected mode and make
* inter-segment jump to the protected mode code.
*/
.code16
.align 4096
.globl sipihandler
sipihandler:
_real:
ljmp $0x0, $_endofheader
_startofheader:
NOP; NOP; NOP
.quad 0xa5a5a5a5a5a5a5a5
_gdt32p:
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x00cf9a000000ffff /* CS */
.quad 0x00cf92000000ffff /* DS */
.quad 0x0020980000000000 /* .long mode CS */
_gdtptr32p:
.word 4*8-1 /* includes .long mode */
.long _gdt32p
_gdt64:
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0020980000000000 /* CS */
.quad 0x0000800000000000 /* DS */
_gdtptr64v:
.word 3*8-1
.quad _gdt64
_endofheader:
mov %cs, %ax
mov %ax, %ds
lgdt _gdtptr32p /* load a basic gdt */
mov %cr0, %eax
or $Pe, %ax
mov %eax, %cr0 /* turn on protected mode */
jmp 1f
1:
mov $(SSEL(SiDS, SsTIGDT|SsRPL0)), %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
ljmpl $8, $_protected /* 8 = SSEL(SiCS, SsTIGDT|SsRPL0) */
/*
* Protected mode. Welcome to 1982.
* Get the local APIC ID from the memory mapped APIC
* and use it to locate the index to the parameter vector;
* load the PDB with the page table address from the
* information vector;
* make an identity map for the inter-segment jump below,
* using the stack space to hold a temporary PDP and PD;
* enable and activate .long mode;
* make an inter-segment jump to the .long mode code.
*/
.code32
/*
* Macros for accessing page table entries; must turn
* the C-style array-index macros into a page table byte
* offset.
*/
#define PML4O(v) ((PTLX((v), 3))<<3)
#define PDPO(v) ((PTLX((v), 2))<<3)
#define PDO(v) ((PTLX((v), 1))<<3)
#define PTO(v) ((PTLX((v), 0))<<3)
_protected:
mov $0xfee00000, %ebp /* apicbase */
mov 0x20(%ebp), %ebp /* Id */
shr $0x18, %ebp /* becomes RARG later */
mov %ebp, %eax /* apicno */
imul $0x20, %eax, %eax /* [apicno] */
mov $_real, %ebx
add $0x1000, %ebx /* sipi */
add %eax, %ebx /* sipi[apicno] */
mov (%ebx), %esi /* sipi[apicno].pml4 */
mov %esi, %eax
mov %eax, %cr3 /* load the mmu */
mov %eax, %edx
sub $MACHSTKSZ, %edx /* PDP for identity map */
add $(PteRW|PteP), %edx
mov %edx, PML4O(0)(%eax) /* PML4E for identity map */
sub $MACHSTKSZ, %eax /* PDP for identity map */
add $PTSZ, %edx
mov %edx, PDPO(0)(%eax) /* PDPE for identity map */
mov $(PtePS|PteRW|PteP), %edx
add $PTSZ, %eax /* PD for identity map */
mov %edx, PDO(0)(%eax) /* PDE for identity 0-[24]MiB */
/*
* Enable and activate .long Mode. From the manual:
* make sure Page Size Extentions are off, and Page Global
* Extensions and Physical Address Extensions are on in CR4;
* set .long Mode Enable in the Extended Feature Enable MSR;
* set Paging Enable in CR0;
* make an inter-segment jump to the .long Mode code.
* It's all in 32-bit mode until the jump is made.
*/
_lme:
mov %cr4, %eax
and $~Pse, %eax /* Page Size */
or $(Pge|Pae), %eax /* Page Global, Phys. Address */
mov %eax, %cr4
mov $Efer, %ecx /* Extended Feature Enable */
rdmsr
or $Lme, %eax /* .long Mode Enable */
wrmsr
mov %cr0, %edx
and $~(Cd|Nw|Ts|Mp), %edx
or $(Pg|Wp), %edx /* Paging Enable */
mov %edx, %cr0
ljmp $0x18, $_identity /* 0x18 = SSEL(3, SsTIGDT|SsRPL0) */
/*
* .long mode. Welcome to 2003.
* Jump out of the identity map space;
* load a proper .long mode GDT;
* zap the identity map;
* initialise the stack, RMACH, RUSER,
* and call the C startup code.
*/
.code64
_identity:
mov $(_start64v+KZERO), %rax
jmpq *%rax
_start64v:
mov $_gdtptr64v, %rax
lgdt (%rax)
xor %rdx, %rdx /* DX is 0 from here on */
mov %edx, %ds /* not used in .long mode */
mov %edx, %es /* not used in .long mode */
mov %edx, %fs
mov %edx, %gs
mov %edx, %ss /* not used in .long mode */
mov %esi, %esi /* sipi[apicno].pml4 */
mov %rsi, %rax
add $KZERO, %rax /* PML4 */
mov %rdx, PML4O(0)(%rax) /* zap identity map */
mov %rsi, %cr3 /* flush TLB */
add $KZERO, %rbx /* &sipi[apicno] */
mov 8(%rbx), %rsp /* sipi[apicno].stack */
push %rdx /* clear flags */
popfq
mov %ebp, %ebp /* APIC ID */
push %rbp /* apicno */
mov 16(%rbx), %r15 /* sipi[apicno].mach */
mov %rdx, %r14
mov 24(%rbx), %rax /* sipi[apicno].pc */
callq *%rax /* (*sipi[apicno].pc)(apicno) */
_ndnr:
jmp _ndnr
2017-01-10 01:37:55 +01:00
.globl sipihandlerend
sipihandlerend:
jmp sipihandlerend