#include <sys/asm_linkage.h>
#include <sys/asm_misc.h>
#include <sys/regset.h>
#include <sys/privregs.h>
#include <sys/x86_archext.h>
#include <sys/cpr_wakecode.h>
#include <sys/segments.h>
#include "assym.h"
#ifdef DEBUG
#define LED 1
#define SERIAL 1
#endif
#ifdef DEBUG
#define COM1 0x3f8
#define COM2 0x2f8
#define WC_COM COM2
#define WC_LED 0x80
#define DLL 0
#define DLH 1
#define LCR 3
#define MCR 4
#define DLAB 0x80
#define B9600L 0X0c
#define B9600H 0X0
#define DTR 0x01
#define RTS 0x02
#define STOP1 0x00
#define BITS8 0x03
#endif
ENTRY_NP(wc_save_context)
movq (%rsp), %rdx / return address
movq %rdx, WC_RETADDR(%rdi)
pushq %rbp
movq %rsp,%rbp
movq %rdi, WC_VIRTADDR(%rdi)
movq %rdi, WC_RDI(%rdi)
movq %rdx, WC_RDX(%rdi)
/ stash everything else we need
sgdt WC_GDT(%rdi)
sidt WC_IDT(%rdi)
sldt WC_LDT(%rdi)
str WC_TR(%rdi)
movq %cr0, %rdx
movq %rdx, WC_CR0(%rdi)
movq %cr3, %rdx
movq %rdx, WC_CR3(%rdi)
movq %cr4, %rdx
movq %rdx, WC_CR4(%rdi)
movq %cr8, %rdx
movq %rdx, WC_CR8(%rdi)
movq %r8, WC_R8(%rdi)
movq %r9, WC_R9(%rdi)
movq %r10, WC_R10(%rdi)
movq %r11, WC_R11(%rdi)
movq %r12, WC_R12(%rdi)
movq %r13, WC_R13(%rdi)
movq %r14, WC_R14(%rdi)
movq %r15, WC_R15(%rdi)
movq %rax, WC_RAX(%rdi)
movq %rbp, WC_RBP(%rdi)
movq %rbx, WC_RBX(%rdi)
movq %rcx, WC_RCX(%rdi)
movq %rsi, WC_RSI(%rdi)
movq %rsp, WC_RSP(%rdi)
movw %ss, WC_SS(%rdi)
movw %cs, WC_CS(%rdi)
movw %ds, WC_DS(%rdi)
movw %es, WC_ES(%rdi)
movq $0, %rcx / save %fs register
movw %fs, %cx
movq %rcx, WC_FS(%rdi)
movl $MSR_AMD_FSBASE, %ecx
rdmsr
movl %eax, WC_FSBASE(%rdi)
movl %edx, WC_FSBASE+4(%rdi)
movq $0, %rcx / save %gs register
movw %gs, %cx
movq %rcx, WC_GS(%rdi)
movl $MSR_AMD_GSBASE, %ecx / save gsbase msr
rdmsr
movl %eax, WC_GSBASE(%rdi)
movl %edx, WC_GSBASE+4(%rdi)
movl $MSR_AMD_KGSBASE, %ecx / save kgsbase msr
rdmsr
movl %eax, WC_KGSBASE(%rdi)
movl %edx, WC_KGSBASE+4(%rdi)
movq %gs:CPU_ID, %rax / save current cpu id
movq %rax, WC_CPU_ID(%rdi)
pushfq
popq WC_EFLAGS(%rdi)
wbinvd / flush the cache
mfence
movq $1, %rax / at suspend return 1
leave
ret
SET_SIZE(wc_save_context)
ENTRY_NP(wc_rm_start)
.code32
cli
movw %cs, %ax
movw %ax, %ds / establish ds ...
movw %ax, %ss / ... and ss:esp
D16 movl $WC_STKSTART, %esp
/ using the following value blows up machines! - DO NOT USE
/ D16 movl 0xffc, %esp
#if LED
D16 movl $WC_LED, %edx
D16 movb $0xd1, %al
outb (%dx)
#endif
#if SERIAL
D16 movl $WC_COM, %edx
D16 movb $0x61, %al
outb (%dx)
#endif
D16 call cominit
movl %cr0, %eax
D16 orl $_CONST(CR0_PE|CR0_WP|CR0_AM), %eax
movl %eax, %cr0
jmp pestart
pestart:
#if LED
D16 movl $WC_LED, %edx
D16 movb $0xd2, %al
outb (%dx)
#endif
#if SERIAL
D16 movl $WC_COM, %edx
D16 movb $0x62, %al
outb (%dx)
#endif
#if LED
D16 movl $WC_LED, %edx
D16 movb $0xd3, %al
outb (%dx)
#endif
#if SERIAL
D16 movl $WC_COM, %edx
D16 movb $0x63, %al
outb (%dx)
#endif
movl %cr4, %eax
A16 D16 orl CR4OFF, %eax
D16 orl $CR4_PAE, %eax
movl %eax, %cr4
#if LED
D16 movl $WC_LED, %edx
D16 movb $0xd4, %al
outb (%dx)
#endif
#if SERIAL
D16 movl $WC_COM, %edx
D16 movb $0x64, %al
outb (%dx)
#endif
A16 D16 movl CR3OFF, %eax
movl %eax, %cr3
D16 movl $MSR_AMD_EFER, %ecx
rdmsr
D16 orl $AMD_EFER_LME, %eax
wrmsr
#if LED
D16 movl $WC_LED, %edx
D16 movb $0xd5, %al
outb (%dx)
#endif
#if SERIAL
D16 movl $WC_COM, %edx
D16 movb $0x65, %al
outb (%dx)
#endif
movl %cr0, %eax
D16 orl $CR0_PG, %eax
movl %eax, %cr0
jmp long_mode_active
long_mode_active:
#if LED
D16 movl $WC_LED, %edx
D16 movb $0xd6, %al
outb (%dx)
#endif
#if SERIAL
D16 movl $WC_COM, %edx
D16 movb $0x66, %al
outb (%dx)
#endif
A16 D16 lgdt TEMPGDTOFF
A16 D16 lidt TEMPIDTOFF
#if LED
D16 movl $WC_LED, %edx
D16 movb $0xd7, %al
outb (%dx)
#endif
#if SERIAL
D16 movl $WC_COM, %edx
D16 movb $0x67, %al
outb (%dx)
#endif
D16 pushl $TEMP_CS64_SEL
A16 D16 pushl LM64OFF
D16 lret
vgainit:
D16 ret
kbdinit:
D16 ret
cominit:
/ init COM1 & COM2
#if DEBUG
/ select COM1
D16 movl $_CONST(COM1+LCR), %edx
D16 movb $DLAB, %al / divisor latch
outb (%dx)
D16 movl $_CONST(COM1+DLL), %edx / divisor latch lsb
D16 movb $B9600L, %al / divisor latch
outb (%dx)
D16 movl $_CONST(COM1+DLH), %edx / divisor latch hsb
D16 movb $B9600H, %al / divisor latch
outb (%dx)
D16 movl $_CONST(COM1+LCR), %edx / select COM1
D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
outb (%dx)
D16 movl $_CONST(COM1+MCR), %edx / select COM1
D16 movb $_CONST(RTS|DTR), %al / data term ready & req to send
outb (%dx)
/ select COM2
D16 movl $_CONST(COM2+LCR), %edx
D16 movb $DLAB, %al / divisor latch
outb (%dx)
D16 movl $_CONST(COM2+DLL), %edx / divisor latch lsb
D16 movb $B9600L, %al / divisor latch
outb (%dx)
D16 movl $_CONST(COM2+DLH), %edx / divisor latch hsb
D16 movb $B9600H, %al / divisor latch
outb (%dx)
D16 movl $_CONST(COM2+LCR), %edx / select COM1
D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
outb (%dx)
D16 movl $_CONST(COM2+MCR), %edx / select COM1
D16 movb $_CONST(RTS|DTR), %al / data term ready & req to send
outb (%dx)
#endif
D16 ret
.code64
.globl wc_long_mode_64
wc_long_mode_64:
#if LED
movw $WC_LED, %dx
movb $0xd8, %al
outb (%dx)
#endif
#if SERIAL
movw $WC_COM, %dx
movb $0x68, %al
outb (%dx)
#endif
.globl rm_platter_pa
movl rm_platter_pa, %eax
lgdtq GDTROFF(%rax)
/ JAN
/ the following is wrong! need to figure out MP systems
/ movl CPUNOFF(%rax), %r11d
addq %rax, %rsp
#if LED
movw $WC_LED, %dx
movb $0xd9, %al
outb (%dx)
#endif
/ JAN this should produce 'i' but we get 'g' instead ???
#if SERIAL
movw $WC_COM, %dx
movb $0x69, %al
outb (%dx)
#endif
pushq $KCS_SEL
pushq $kernel_wc_code
lretq
.globl kernel_wc_code
kernel_wc_code:
#if LED
movw $WC_LED, %dx
movb $0xda, %al
outb (%dx)
#endif
/ JAN this should produce 'j' but we get 'g' instead ???
#if SERIAL
movw $WC_COM, %dx
movb $0x6a, %al
outb (%dx)
#endif
.globl rm_platter_va
movq rm_platter_va, %rbx
addq $WC_CPU, %rbx
#if LED
movw $WC_LED, %dx
movb $0xdb, %al
outb (%dx)
#endif
#if SERIAL
movw $WC_COM, %dx
movw $0x6b, %ax
outb (%dx)
#endif
lidtq WC_IDT(%rbx)
#if LED
movw $WC_LED, %dx
movb $0xdc, %al
outb (%dx)
#endif
#if SERIAL
movw $WC_COM, %dx
movw $0x6c, %ax
outb (%dx)
#endif
movw $KDS_SEL, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
btl $X86FSET_NX, x86_featureset(%rip)
jnc 1f
movl $MSR_AMD_EFER, %ecx
rdmsr
orl $AMD_EFER_NXE, %eax
wrmsr
1:
movq WC_CR4(%rbx), %rax / restore full cr4 (with Global Enable)
movq %rax, %cr4
lldt WC_LDT(%rbx)
movzwq WC_TR(%rbx), %rax / clear TSS busy bit
addq WC_GDT+2(%rbx), %rax
andl $0xfffffdff, 4(%rax)
movq 4(%rax), %rcx
ltr WC_TR(%rbx)
#if LED
movw $WC_LED, %dx
movb $0xdd, %al
outb (%dx)
#endif
#if SERIAL
movw $WC_COM, %dx
movw $0x6d, %ax
outb (%dx)
#endif
/ restore %fsbase %gsbase %kgbase registers using wrmsr instruction
movq WC_FS(%rbx), %rcx / restore fs register
movw %cx, %fs
movl $MSR_AMD_FSBASE, %ecx
movl WC_FSBASE(%rbx), %eax
movl WC_FSBASE+4(%rbx), %edx
wrmsr
movq WC_GS(%rbx), %rcx / restore gs register
movw %cx, %gs
movl $MSR_AMD_GSBASE, %ecx / restore gsbase msr
movl WC_GSBASE(%rbx), %eax
movl WC_GSBASE+4(%rbx), %edx
wrmsr
movl $MSR_AMD_KGSBASE, %ecx / restore kgsbase msr
movl WC_KGSBASE(%rbx), %eax
movl WC_KGSBASE+4(%rbx), %edx
wrmsr
movq WC_CR0(%rbx), %rdx
movq %rdx, %cr0
movq WC_CR3(%rbx), %rdx
movq %rdx, %cr3
movq WC_CR8(%rbx), %rdx
movq %rdx, %cr8
#if LED
movw $WC_LED, %dx
movb $0xde, %al
outb (%dx)
#endif
#if SERIAL
movw $WC_COM, %dx
movb $0x6e, %al
outb (%dx)
#endif
movq %rsp, %rbp
call i_cpr_bootcpuid
cmpl %eax, WC_CPU_ID(%rbx)
je 2f
movq %gs:CPU_THREAD, %rdi
movq WC_SAVED_STACK(%rbx), %rsi
call i_cpr_restore_stack
2:
movq WC_RSP(%rbx), %rsp / restore stack pointer
movq %rsp, %rbp
cmpq $0, ap_mlsetup
je 3f
leaq ap_mlsetup, %rax
INDIRECT_CALL_REG(rax)
3:
leaq cpr_start_cpu_func, %rax
INDIRECT_CALL_REG(rax)
/ restore %rbx to the value it ahd before we called the functions above
movq rm_platter_va, %rbx
addq $WC_CPU, %rbx
movq WC_R8(%rbx), %r8
movq WC_R9(%rbx), %r9
movq WC_R10(%rbx), %r10
movq WC_R11(%rbx), %r11
movq WC_R12(%rbx), %r12
movq WC_R13(%rbx), %r13
movq WC_R14(%rbx), %r14
movq WC_R15(%rbx), %r15
/ movq WC_RAX(%rbx), %rax
movq WC_RBP(%rbx), %rbp
movq WC_RCX(%rbx), %rcx
/ movq WC_RDX(%rbx), %rdx
movq WC_RDI(%rbx), %rdi
movq WC_RSI(%rbx), %rsi
/ assume that %cs does not need to be restored
/ %ds, %es & %ss are ignored in 64bit mode
movw WC_SS(%rbx), %ss
movw WC_DS(%rbx), %ds
movw WC_ES(%rbx), %es
#if LED
movw $WC_LED, %dx
movb $0xdf, %al
outb (%dx)
#endif
#if SERIAL
movw $WC_COM, %dx
movb $0x6f, %al
outb (%dx)
#endif
movq WC_RBP(%rbx), %rbp
movq WC_RSP(%rbx), %rsp
#if LED
movw $WC_LED, %dx
movb $0xe0, %al
outb (%dx)
#endif
#if SERIAL
movw $WC_COM, %dx
movb $0x70, %al
outb (%dx)
#endif
movq WC_RCX(%rbx), %rcx
pushq WC_EFLAGS(%rbx) / restore flags
popfq
#if LED
movw $WC_LED, %dx
movb $0xe1, %al
outb (%dx)
#endif
#if SERIAL
movw $WC_COM, %dx
movb $0x71, %al
outb (%dx)
#endif
movq %rbx, %rax
movq WC_RDX(%rax), %rdx
movq WC_RBX(%rax), %rbx
leave
movq WC_RETADDR(%rax), %rax
movq %rax, (%rsp) / return to caller of wc_save_context
xorl %eax, %eax / at wakeup return 0
ret
SET_SIZE(wc_rm_start)
ENTRY_NP(asmspin)
movl %edi, %ecx
A1:
loop A1
SET_SIZE(asmspin)
.globl wc_rm_end
wc_rm_end:
nop