mirror of https://gitlab.com/nakst/essence
934 lines
15 KiB
ArmAsm
934 lines
15 KiB
ArmAsm
; This file is part of the Essence operating system.
|
|
; It is released under the terms of the MIT license -- see LICENSE.md.
|
|
; Written by: nakst.
|
|
|
|
[bits 64]
|
|
|
|
[global ArchSwitchContext]
|
|
[global GetCurrentThread]
|
|
[global GetLocalStorage]
|
|
[global MMArchSafeCopy]
|
|
[global ProcessorAPStartup]
|
|
[global ProcessorAreInterruptsEnabled]
|
|
[global ProcessorDebugOutputByte]
|
|
[global ProcessorDisableInterrupts]
|
|
[global ProcessorEnableInterrupts]
|
|
[global ProcessorFakeTimerInterrupt]
|
|
[global ProcessorFlushCodeCache]
|
|
[global ProcessorGetRBP]
|
|
[global ProcessorGetRSP]
|
|
[global ProcessorHalt]
|
|
[global ProcessorIn16]
|
|
[global ProcessorIn32]
|
|
[global ProcessorIn8]
|
|
[global ProcessorInstallTSS]
|
|
[global ProcessorInvalidateAllPages]
|
|
[global ProcessorInvalidatePage]
|
|
[global ProcessorOut16]
|
|
[global ProcessorOut32]
|
|
[global ProcessorOut8]
|
|
[global ProcessorReadCR3]
|
|
[global ProcessorReadMXCSR]
|
|
[global ProcessorReadTimeStamp]
|
|
[global ProcessorReset]
|
|
[global ProcessorSetAddressSpace]
|
|
[global ProcessorSetLocalStorage]
|
|
[global ProcessorSetThreadStorage]
|
|
[global _KThreadTerminate]
|
|
[global _start]
|
|
[global gdt_data]
|
|
[global pagingNXESupport]
|
|
[global pagingPCIDSupport]
|
|
[global pagingSMEPSupport]
|
|
[global pagingTCESupport]
|
|
[global processorGDTR]
|
|
[global simdSSE3Support]
|
|
[global simdSSSE3Support]
|
|
[global timeStampCounterSynchronizationValue]
|
|
|
|
[extern ArchNextTimer]
|
|
[extern InterruptHandler]
|
|
[extern KThreadTerminate]
|
|
[extern KernelInitialise]
|
|
[extern PostContextSwitch]
|
|
[extern SetupProcessor2]
|
|
[extern Syscall]
|
|
[extern installationID]
|
|
[extern PCSetupCOM1]
|
|
[extern PCDisablePIC]
|
|
[extern PCProcessMemoryMap]
|
|
[extern bootloaderID]
|
|
[extern bootloaderInformationOffset]
|
|
|
|
[section .bss]
|
|
|
|
align 16
|
|
|
|
%define stack_size 16384
|
|
stack: resb stack_size
|
|
|
|
%define idt_size 4096
|
|
idt_data: resb idt_size
|
|
|
|
%define cpu_local_storage_size 8192
|
|
; Array of pointers to the CPU local states
|
|
cpu_local_storage: resb cpu_local_storage_size
|
|
|
|
[section .data]
|
|
|
|
idt:
|
|
.limit: dw idt_size - 1
|
|
.base: dq idt_data
|
|
|
|
cpu_local_storage_index:
|
|
dq 0
|
|
|
|
pagingNXESupport:
|
|
dd 1
|
|
pagingPCIDSupport:
|
|
dd 1
|
|
pagingSMEPSupport:
|
|
dd 1
|
|
pagingTCESupport:
|
|
dd 1
|
|
simdSSE3Support:
|
|
dd 1
|
|
simdSSSE3Support:
|
|
dd 1
|
|
|
|
align 16
|
|
processorGDTR:
|
|
dq 0
|
|
dq 0
|
|
|
|
[section .text]
|
|
|
|
_start:
|
|
mov rax,0x63
|
|
mov fs,ax
|
|
mov gs,ax
|
|
|
|
; Save the bootloader ID.
|
|
mov rax,bootloaderID
|
|
mov [rax],rsi
|
|
|
|
; The MBR bootloader does not know the address of the RSDP.
|
|
cmp rdi,0
|
|
jne .standard_acpi
|
|
mov [0x7FE8],rdi
|
|
.standard_acpi:
|
|
|
|
; Save the bootloader information offset.
|
|
mov rax,bootloaderInformationOffset
|
|
mov [rax],rdi
|
|
|
|
; Install a stack
|
|
mov rsp,stack + stack_size
|
|
|
|
; Load the installation ID.
|
|
mov rbx,installationID
|
|
mov rax,[rdi + 0x7FF0]
|
|
mov [rbx],rax
|
|
mov rax,[rdi + 0x7FF8]
|
|
mov [rbx + 8],rax
|
|
|
|
; Unmap the identity paging the bootloader used
|
|
mov rax,0xFFFFFF7FBFDFE000
|
|
mov qword [rax],0
|
|
mov rax,cr3
|
|
mov cr3,rax
|
|
|
|
call PCSetupCOM1
|
|
call PCDisablePIC
|
|
call PCProcessMemoryMap
|
|
|
|
; Install the interrupt handlers
|
|
%macro INSTALL_INTERRUPT_HANDLER 1
|
|
mov rbx,(%1 * 16) + idt_data
|
|
mov rdx,InterruptHandler%1
|
|
call InstallInterruptHandler
|
|
%endmacro
|
|
%assign i 0
|
|
%rep 256
|
|
INSTALL_INTERRUPT_HANDLER i
|
|
%assign i i+1
|
|
%endrep
|
|
|
|
; Save the location of the bootstrap GDT
|
|
mov rcx,processorGDTR
|
|
sgdt [rcx]
|
|
|
|
; First stage of processor initilisation
|
|
call SetupProcessor1
|
|
|
|
; Call the KernelInitialise function
|
|
and rsp,~0xF
|
|
call KernelInitialise
|
|
|
|
ProcessorReady:
|
|
; Set the timer and become this CPU's idle thread.
|
|
mov rdi,1
|
|
call ArchNextTimer
|
|
jmp ProcessorIdle
|
|
|
|
SetupProcessor1:
|
|
.enable_cpu_features:
|
|
; Enable no-execute support, if available
|
|
mov eax,0x80000001
|
|
cpuid
|
|
and edx,1 << 20
|
|
shr edx,20
|
|
mov rax,pagingNXESupport
|
|
and [rax],edx
|
|
cmp edx,0
|
|
je .no_paging_nxe_support
|
|
mov ecx,0xC0000080
|
|
rdmsr
|
|
or eax,1 << 11
|
|
wrmsr
|
|
.no_paging_nxe_support:
|
|
|
|
; x87 FPU
|
|
fninit
|
|
mov rax,.cw
|
|
fldcw [rax]
|
|
jmp .cwa
|
|
.cw: dw 0x037A
|
|
.cwa:
|
|
|
|
; Enable SMEP support, if available
|
|
; This prevents the kernel from executing userland pages
|
|
; TODO Test this: neither Bochs or Qemu seem to support it?
|
|
xor eax,eax
|
|
cpuid
|
|
cmp eax,7
|
|
jb .no_smep_support
|
|
mov eax,7
|
|
xor ecx,ecx
|
|
cpuid
|
|
and ebx,1 << 7
|
|
shr ebx,7
|
|
mov rax,pagingSMEPSupport
|
|
and [rax],ebx
|
|
cmp ebx,0
|
|
je .no_smep_support
|
|
mov word [rax],2
|
|
mov rax,cr4
|
|
or rax,1 << 20
|
|
mov cr4,rax
|
|
.no_smep_support:
|
|
|
|
; Enable PCID support, if available
|
|
mov eax,1
|
|
xor ecx,ecx
|
|
cpuid
|
|
and ecx,1 << 17
|
|
shr ecx,17
|
|
mov rax,pagingPCIDSupport
|
|
and [rax],ecx
|
|
cmp ecx,0
|
|
je .no_pcid_support
|
|
mov rax,cr4
|
|
or rax,1 << 17
|
|
mov cr4,rax
|
|
.no_pcid_support:
|
|
|
|
; Enable global pages
|
|
mov rax,cr4
|
|
or rax,1 << 7
|
|
mov cr4,rax
|
|
|
|
; Enable TCE support, if available
|
|
mov eax,0x80000001
|
|
xor ecx,ecx
|
|
cpuid
|
|
and ecx,1 << 17
|
|
shr ecx,17
|
|
mov rax,pagingTCESupport
|
|
and [rax],ecx
|
|
cmp ecx,0
|
|
je .no_tce_support
|
|
mov ecx,0xC0000080
|
|
rdmsr
|
|
or eax,1 << 15
|
|
wrmsr
|
|
.no_tce_support:
|
|
|
|
; Enable write protect, so copy-on-write works in the kernel, and MMArchSafeCopy will page fault in read-only regions.
|
|
mov rax,cr0
|
|
or rax,1 << 16
|
|
mov cr0,rax
|
|
|
|
; Enable MMX, SSE and SSE2
|
|
; These features are all guaranteed to be present on a x86_64 CPU
|
|
mov rax,cr0
|
|
mov rbx,cr4
|
|
and rax,~4
|
|
or rax,2
|
|
or rbx,512 + 1024
|
|
mov cr0,rax
|
|
mov cr4,rbx
|
|
|
|
; Detect SSE3 and SSSE3, if available.
|
|
mov eax,1
|
|
cpuid
|
|
test ecx,1 << 0
|
|
jnz .has_sse3
|
|
mov rax,simdSSE3Support
|
|
and byte [rax],0
|
|
.has_sse3:
|
|
test ecx,1 << 9
|
|
jnz .has_ssse3
|
|
mov rax,simdSSSE3Support
|
|
and byte [rax],0
|
|
.has_ssse3:
|
|
|
|
; Enable system-call extensions (SYSCALL and SYSRET).
|
|
mov ecx,0xC0000080
|
|
rdmsr
|
|
or eax,1
|
|
wrmsr
|
|
add ecx,1
|
|
rdmsr
|
|
mov edx,0x005B0048
|
|
wrmsr
|
|
add ecx,1
|
|
mov rdx,SyscallEntry
|
|
mov rax,rdx
|
|
shr rdx,32
|
|
wrmsr
|
|
add ecx,2
|
|
rdmsr
|
|
mov eax,(1 << 10) | (1 << 9) ; Clear direction and interrupt flag when we enter ring 0.
|
|
wrmsr
|
|
|
|
; Assign PAT2 to WC.
|
|
mov ecx,0x277
|
|
xor rax,rax
|
|
xor rdx,rdx
|
|
rdmsr
|
|
and eax,0xFFF8FFFF
|
|
or eax,0x00010000
|
|
wrmsr
|
|
|
|
.setup_cpu_local_storage:
|
|
mov ecx,0xC0000101
|
|
mov rax,cpu_local_storage
|
|
mov rdx,cpu_local_storage
|
|
shr rdx,32
|
|
mov rdi,cpu_local_storage_index
|
|
add rax,[rdi]
|
|
add qword [rdi],32 ; Space for 4 8-byte values at gs:0 - gs:31
|
|
wrmsr
|
|
|
|
.load_idtr:
|
|
; Load the IDTR
|
|
mov rax,idt
|
|
lidt [rax]
|
|
sti
|
|
|
|
.enable_apic:
|
|
; Enable the APIC!
|
|
; Since we're on AMD64, we know that the APIC will be present.
|
|
mov ecx,0x1B
|
|
rdmsr
|
|
or eax,0x800
|
|
wrmsr
|
|
and eax,~0xFFF
|
|
mov edi,eax
|
|
|
|
; Set the spurious interrupt vector to 0xFF
|
|
mov rax,0xFFFFFE00000000F0 ; LOW_MEMORY_MAP_START + 0xF0
|
|
add rax,rdi
|
|
mov ebx,[rax]
|
|
or ebx,0x1FF
|
|
mov [rax],ebx
|
|
|
|
; Use the flat processor addressing model
|
|
mov rax,0xFFFFFE00000000E0 ; LOW_MEMORY_MAP_START + 0xE0
|
|
add rax,rdi
|
|
mov dword [rax],0xFFFFFFFF
|
|
|
|
; Make sure that no external interrupts are masked
|
|
xor rax,rax
|
|
mov cr8,rax
|
|
|
|
ret
|
|
|
|
SyscallEntry:
|
|
mov rsp,[gs:8]
|
|
sti
|
|
|
|
mov ax,0x50
|
|
mov ds,ax
|
|
mov es,ax
|
|
|
|
; Preserve RCX, R11, R12 and RBX.
|
|
push rcx
|
|
push r11
|
|
push r12
|
|
mov rax,rsp
|
|
push rbx
|
|
push rax
|
|
|
|
; Arguments in RDI, RSI, RDX, R8, R9. (RCX contains return address).
|
|
; Return value in RAX.
|
|
mov rbx,rsp
|
|
and rsp,~0xF
|
|
call Syscall
|
|
mov rsp,rbx
|
|
|
|
; Disable maskable interrupts.
|
|
cli
|
|
|
|
; Return to long mode. (Address in RCX).
|
|
add rsp,8
|
|
push rax
|
|
mov ax,0x63
|
|
mov ds,ax
|
|
mov es,ax
|
|
pop rax
|
|
pop rbx
|
|
pop r12 ; User RSP
|
|
pop r11
|
|
pop rcx ; Return address
|
|
db 0x48
|
|
sysret
|
|
|
|
ProcessorFakeTimerInterrupt:
|
|
int 0x40
|
|
ret
|
|
|
|
ProcessorDisableInterrupts:
|
|
mov rax,14 ; Still allow important IPIs to go through.
|
|
mov cr8,rax
|
|
sti ; TODO Where is this necessary? Is is a performance issue?
|
|
ret
|
|
|
|
ProcessorEnableInterrupts:
|
|
; WARNING: Changing this mechanism also requires update in x86_64.cpp, when deciding if we should re-enable interrupts on exception.
|
|
mov rax,0
|
|
mov cr8,rax
|
|
sti ; TODO Where is this necessary? Is is a performance issue?
|
|
ret
|
|
|
|
ProcessorAreInterruptsEnabled:
|
|
pushf
|
|
pop rax
|
|
and rax,0x200
|
|
shr rax,9
|
|
|
|
mov rdx,cr8
|
|
cmp rdx,0
|
|
je .done
|
|
mov rax,0
|
|
.done:
|
|
|
|
; pushf
|
|
; pop rax
|
|
; and rax,0x200
|
|
; shr rax,9
|
|
ret
|
|
|
|
ProcessorHalt:
|
|
cli
|
|
hlt
|
|
jmp ProcessorHalt
|
|
|
|
ProcessorOut8:
|
|
mov rdx,rdi
|
|
mov rax,rsi
|
|
out dx,al
|
|
ret
|
|
|
|
ProcessorIn8:
|
|
mov rdx,rdi
|
|
xor rax,rax
|
|
in al,dx
|
|
ret
|
|
|
|
ProcessorOut16:
|
|
mov rdx,rdi
|
|
mov rax,rsi
|
|
out dx,ax
|
|
ret
|
|
|
|
ProcessorIn16:
|
|
mov rdx,rdi
|
|
xor rax,rax
|
|
in ax,dx
|
|
ret
|
|
|
|
ProcessorOut32:
|
|
mov rdx,rdi
|
|
mov rax,rsi
|
|
out dx,eax
|
|
ret
|
|
|
|
ProcessorIn32:
|
|
mov rdx,rdi
|
|
xor rax,rax
|
|
in eax,dx
|
|
ret
|
|
|
|
ProcessorInvalidatePage:
|
|
invlpg [rdi]
|
|
ret
|
|
|
|
ProcessorInvalidateAllPages:
|
|
; Toggle CR4.PGE to invalidate all TLB entries, including global entries.
|
|
mov rax,cr4
|
|
and rax,~(1 << 7)
|
|
mov cr4,rax
|
|
or rax,1 << 7
|
|
mov cr4,rax
|
|
ret
|
|
|
|
ProcessorIdle:
|
|
sti
|
|
hlt
|
|
jmp ProcessorIdle
|
|
|
|
GetLocalStorage:
|
|
mov rax,[gs:0]
|
|
ret
|
|
|
|
GetCurrentThread:
|
|
mov rax,[gs:16]
|
|
ret
|
|
|
|
ProcessorSetLocalStorage:
|
|
mov [gs:0],rdi
|
|
ret
|
|
|
|
ProcessorSetThreadStorage:
|
|
push rdx
|
|
push rcx
|
|
mov rcx,0xC0000100 ; set fs base
|
|
mov rdx,rdi
|
|
mov rax,rdi
|
|
shr rdx,32
|
|
wrmsr ; to edx:eax (from rdi)
|
|
pop rcx
|
|
pop rdx
|
|
ret
|
|
|
|
InstallInterruptHandler:
|
|
mov word [rbx + 0],dx
|
|
mov word [rbx + 2],0x48
|
|
mov word [rbx + 4],0x8E00
|
|
shr rdx,16
|
|
mov word [rbx + 6],dx
|
|
shr rdx,16
|
|
mov qword [rbx + 8],rdx
|
|
|
|
ret
|
|
|
|
%macro INTERRUPT_HANDLER 1
|
|
InterruptHandler%1:
|
|
push dword 0 ; A fake error code
|
|
push dword %1 ; The interrupt number
|
|
jmp ASMInterruptHandler
|
|
%endmacro
|
|
|
|
%macro INTERRUPT_HANDLER_EC 1
|
|
InterruptHandler%1:
|
|
; The CPU already pushed an error code
|
|
push dword %1 ; The interrupt number
|
|
jmp ASMInterruptHandler
|
|
%endmacro
|
|
|
|
INTERRUPT_HANDLER 0
|
|
INTERRUPT_HANDLER 1
|
|
INTERRUPT_HANDLER 2
|
|
INTERRUPT_HANDLER 3
|
|
INTERRUPT_HANDLER 4
|
|
INTERRUPT_HANDLER 5
|
|
INTERRUPT_HANDLER 6
|
|
INTERRUPT_HANDLER 7
|
|
INTERRUPT_HANDLER_EC 8
|
|
INTERRUPT_HANDLER 9
|
|
INTERRUPT_HANDLER_EC 10
|
|
INTERRUPT_HANDLER_EC 11
|
|
INTERRUPT_HANDLER_EC 12
|
|
INTERRUPT_HANDLER_EC 13
|
|
INTERRUPT_HANDLER_EC 14
|
|
INTERRUPT_HANDLER 15
|
|
INTERRUPT_HANDLER 16
|
|
INTERRUPT_HANDLER_EC 17
|
|
INTERRUPT_HANDLER 18
|
|
INTERRUPT_HANDLER 19
|
|
INTERRUPT_HANDLER 20
|
|
INTERRUPT_HANDLER 21
|
|
INTERRUPT_HANDLER 22
|
|
INTERRUPT_HANDLER 23
|
|
INTERRUPT_HANDLER 24
|
|
INTERRUPT_HANDLER 25
|
|
INTERRUPT_HANDLER 26
|
|
INTERRUPT_HANDLER 27
|
|
INTERRUPT_HANDLER 28
|
|
INTERRUPT_HANDLER 29
|
|
INTERRUPT_HANDLER 30
|
|
INTERRUPT_HANDLER 31
|
|
|
|
%assign i 32
|
|
%rep 224
|
|
INTERRUPT_HANDLER i
|
|
%assign i i+1
|
|
%endrep
|
|
|
|
ASMInterruptHandler:
|
|
cld
|
|
|
|
push rax
|
|
push rbx
|
|
push rcx
|
|
push rdx
|
|
push rsi
|
|
push rdi
|
|
push rbp
|
|
push r8
|
|
push r9
|
|
push r10
|
|
push r11
|
|
push r12
|
|
push r13
|
|
push r14
|
|
push r15
|
|
|
|
mov rax,cr8
|
|
push rax
|
|
|
|
mov rax,0x123456789ABCDEF
|
|
push rax
|
|
|
|
mov rbx,rsp
|
|
and rsp,~0xF
|
|
fxsave [rsp - 512]
|
|
mov rsp,rbx
|
|
sub rsp,512 + 16
|
|
|
|
xor rax,rax
|
|
mov ax,ds
|
|
push rax
|
|
mov ax,0x10
|
|
mov ds,ax
|
|
mov es,ax
|
|
mov rax,cr2
|
|
push rax
|
|
|
|
mov rdi,rsp
|
|
mov rbx,rsp
|
|
and rsp,~0xF
|
|
call InterruptHandler
|
|
mov rsp,rbx
|
|
xor rax,rax
|
|
|
|
ReturnFromInterruptHandler:
|
|
add rsp,8
|
|
pop rbx
|
|
mov ds,bx
|
|
mov es,bx
|
|
|
|
add rsp,512 + 16
|
|
mov rbx,rsp
|
|
and rbx,~0xF
|
|
fxrstor [rbx - 512]
|
|
|
|
cmp al,0
|
|
je .oldThread
|
|
fninit ; New thread - initialise FPU.
|
|
.oldThread:
|
|
|
|
pop rax
|
|
mov rbx,0x123456789ABCDEF
|
|
cmp rax,rbx
|
|
jne $
|
|
|
|
cli
|
|
pop rax
|
|
mov cr8,rax
|
|
|
|
pop r15
|
|
pop r14
|
|
pop r13
|
|
pop r12
|
|
pop r11
|
|
pop r10
|
|
pop r9
|
|
pop r8
|
|
pop rbp
|
|
pop rdi
|
|
pop rsi
|
|
pop rdx
|
|
pop rcx
|
|
pop rbx
|
|
pop rax
|
|
|
|
add rsp,16
|
|
iretq
|
|
|
|
ProcessorSetAddressSpace:
|
|
mov rdi,[rdi]
|
|
mov rax,cr3
|
|
cmp rax,rdi
|
|
je .cont
|
|
mov cr3,rdi
|
|
.cont:
|
|
ret
|
|
|
|
ProcessorGetRSP:
|
|
mov rax,rsp
|
|
ret
|
|
|
|
ProcessorGetRBP:
|
|
mov rax,rbp
|
|
ret
|
|
|
|
ArchSwitchContext:
|
|
cli
|
|
mov [gs:16],rcx
|
|
mov [gs:8],rdx
|
|
mov rsi,[rsi]
|
|
mov rax,cr3
|
|
cmp rax,rsi
|
|
je .cont
|
|
mov cr3,rsi
|
|
.cont:
|
|
mov rsp,rdi
|
|
mov rsi,r8
|
|
call PostContextSwitch
|
|
jmp ReturnFromInterruptHandler
|
|
|
|
ProcessorReadCR3:
|
|
mov rax,cr3
|
|
ret
|
|
|
|
ProcessorDebugOutputByte:
|
|
%ifdef COM_OUTPUT
|
|
mov dx,0x3F8 + 5
|
|
.WaitRead:
|
|
in al,dx
|
|
and al,0x20
|
|
cmp al,0
|
|
je .WaitRead
|
|
mov dx,0x3F8 + 0
|
|
mov rax,rdi
|
|
out dx,al
|
|
%endif
|
|
ret
|
|
|
|
ProcessorReadTimeStamp:
|
|
rdtsc
|
|
shl rdx,32
|
|
or rax,rdx
|
|
ret
|
|
|
|
ProcessorFlushCodeCache:
|
|
wbinvd
|
|
ret
|
|
|
|
ProcessorReadMXCSR:
|
|
mov rax,.buffer
|
|
stmxcsr [rax]
|
|
mov rax,.buffer
|
|
mov rax,[rax]
|
|
ret
|
|
.buffer: dq 0
|
|
|
|
ProcessorInstallTSS:
|
|
push rbx
|
|
|
|
; Set the location of the TSS in the GDT.
|
|
mov rax,rdi
|
|
mov rbx,rsi
|
|
mov [rax + 56 + 2],bx
|
|
shr rbx,16
|
|
mov [rax + 56 + 4],bl
|
|
shr rbx,8
|
|
mov [rax + 56 + 7],bl
|
|
shr rbx,8
|
|
mov [rax + 56 + 8],rbx
|
|
|
|
; Flush the GDT.
|
|
mov rax,gdt_data.gdt2
|
|
mov rdx,[rax]
|
|
mov [rax],rdi
|
|
mov rdi,gdt_data.gdt
|
|
lgdt [rdi]
|
|
mov [rax],rdx
|
|
|
|
; Flush the TSS.
|
|
mov ax,0x38
|
|
ltr ax
|
|
|
|
pop rbx
|
|
ret
|
|
|
|
MMArchSafeCopy:
|
|
call GetCurrentThread
|
|
mov byte [rax + 0],1 ; see definition of Thread
|
|
mov rcx,rdx
|
|
mov r8,.error ; where to jump to if we get a page fault
|
|
rep movsb
|
|
mov byte [rax + 0],0
|
|
mov al,1
|
|
ret
|
|
.error: ; we got a page fault in a user address, return false
|
|
mov byte [rax + 0],0
|
|
mov al,0
|
|
ret
|
|
|
|
ProcessorReset:
|
|
in al,0x64
|
|
test al,2
|
|
jne ProcessorReset
|
|
mov al,0xFE
|
|
out 0x64,al
|
|
jmp $
|
|
|
|
_KThreadTerminate:
|
|
sub rsp,8
|
|
jmp KThreadTerminate
|
|
|
|
SynchronizeTimeStampCounter:
|
|
mov rdx,[timeStampCounterSynchronizationValue]
|
|
mov rcx,0x8000000000000000
|
|
.loop:
|
|
mov rbx,rdx
|
|
mov rax,[timeStampCounterSynchronizationValue]
|
|
xor rbx,rax
|
|
test rbx,rcx
|
|
jz .loop
|
|
sub rcx,1
|
|
and rax,rcx
|
|
mov ecx,0x10
|
|
mov rdx,rax
|
|
shr rdx,32
|
|
wrmsr
|
|
ret
|
|
timeStampCounterSynchronizationValue: dq 0
|
|
|
|
[bits 16]
|
|
ProcessorAPStartup: ; This function must be less than 4KB in length (see drivers/acpi.cpp)
|
|
mov ax,0x1000
|
|
mov ds,ax
|
|
mov byte [0xFC0],1 ; Indicate we've started.
|
|
mov eax,[0xFF0]
|
|
mov cr3,eax
|
|
lgdt [0x1000 + gdt_data.gdt - gdt_data]
|
|
mov eax,cr0
|
|
or eax,1
|
|
mov cr0,eax
|
|
jmp 0x8:dword (.pmode - ProcessorAPStartup + 0x10000)
|
|
[bits 32]
|
|
.pmode:
|
|
mov eax,cr4
|
|
or eax,32
|
|
mov cr4,eax
|
|
mov ecx,0xC0000080
|
|
rdmsr
|
|
or eax,256
|
|
wrmsr
|
|
mov eax,cr0
|
|
or eax,0x80000000
|
|
mov cr0,eax
|
|
jmp 0x48:(.start_64_bit_mode - ProcessorAPStartup + 0x10000)
|
|
[bits 64]
|
|
.start_64_bit_mode:
|
|
mov rax,.start_64_bit_mode2
|
|
jmp rax
|
|
.start_64_bit_mode2:
|
|
mov rax,0x50
|
|
mov ds,rax
|
|
mov es,rax
|
|
mov ss,rax
|
|
mov rax,0x63
|
|
mov fs,rax
|
|
mov gs,rax
|
|
lgdt [0x10FE0]
|
|
mov rsp,[0x10FD0]
|
|
call SetupProcessor1
|
|
call SynchronizeTimeStampCounter
|
|
mov rdi,[0x10FB0]
|
|
call SetupProcessor2
|
|
mov byte [0x10FC0],2 ; Indicate the BSP can start the next processor.
|
|
and rsp,~0xF
|
|
jmp ProcessorReady
|
|
|
|
gdt_data:
|
|
.null_entry: dq 0
|
|
.code_entry: dd 0xFFFF ; 0x08
|
|
db 0
|
|
dw 0xCF9A
|
|
db 0
|
|
.data_entry: dd 0xFFFF ; 0x10
|
|
db 0
|
|
dw 0xCF92
|
|
db 0
|
|
.code_entry_16: dd 0xFFFF ; 0x18
|
|
db 0
|
|
dw 0x0F9A
|
|
db 0
|
|
.data_entry_16: dd 0xFFFF ; 0x20
|
|
db 0
|
|
dw 0x0F92
|
|
db 0
|
|
.user_code: dd 0xFFFF ; 0x2B
|
|
db 0
|
|
dw 0xCFFA
|
|
db 0
|
|
.user_data: dd 0xFFFF ; 0x33
|
|
db 0
|
|
dw 0xCFF2
|
|
db 0
|
|
.tss: dd 0x68 ; 0x38
|
|
db 0
|
|
dw 0xE9
|
|
db 0
|
|
dq 0
|
|
.code_entry64: dd 0xFFFF ; 0x48
|
|
db 0
|
|
dw 0xAF9A
|
|
db 0
|
|
.data_entry64: dd 0xFFFF ; 0x50
|
|
db 0
|
|
dw 0xAF92
|
|
db 0
|
|
.user_code64: dd 0xFFFF ; 0x5B
|
|
db 0
|
|
dw 0xAFFA
|
|
db 0
|
|
.user_data64: dd 0xFFFF ; 0x63
|
|
db 0
|
|
dw 0xAFF2
|
|
db 0
|
|
.user_code64c: dd 0xFFFF ; 0x6B
|
|
db 0
|
|
dw 0xAFFA
|
|
db 0
|
|
.gdt: dw (gdt_data.gdt - gdt_data - 1)
|
|
.gdt2: dq 0x11000
|
|
|
|
%macro CALL_REGISTER_INDIRECT 1
|
|
[global __x86_indirect_thunk_%1]
|
|
__x86_indirect_thunk_%1:
|
|
jmp %1
|
|
%endmacro
|
|
|
|
CALL_REGISTER_INDIRECT rax
|
|
CALL_REGISTER_INDIRECT rbx
|
|
CALL_REGISTER_INDIRECT rcx
|
|
CALL_REGISTER_INDIRECT rdx
|
|
CALL_REGISTER_INDIRECT rsi
|
|
CALL_REGISTER_INDIRECT rdi
|
|
CALL_REGISTER_INDIRECT rbp
|
|
CALL_REGISTER_INDIRECT r8
|
|
CALL_REGISTER_INDIRECT r9
|
|
CALL_REGISTER_INDIRECT r10
|
|
CALL_REGISTER_INDIRECT r11
|
|
CALL_REGISTER_INDIRECT r12
|
|
CALL_REGISTER_INDIRECT r13
|
|
CALL_REGISTER_INDIRECT r14
|
|
CALL_REGISTER_INDIRECT r15
|