13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2019 Joyent, Inc.
24 */
25
26 #include <sys/asm_linkage.h>
27 #include <sys/asm_misc.h>
28 #include <sys/regset.h>
29 #include <sys/privregs.h>
30 #include <sys/x86_archext.h>
31 #include <sys/cpr_wakecode.h>
32
33 #if !defined(__lint)
34 #include <sys/segments.h>
35 #include "assym.h"
36 #endif
37
38 #ifdef DEBUG
39 #define LED 1
40 #define SERIAL 1
41 #endif /* DEBUG */
42
43 #ifdef DEBUG
44 #define COM1 0x3f8
45 #define COM2 0x2f8
46 #define WC_COM COM2 /* either COM1 or COM2 */
47 #define WC_LED 0x80 /* diagnostic led port ON motherboard */
48
49 /*
50 * defined as offsets from the data register
51 */
52 #define DLL 0 /* divisor latch (lsb) */
53 #define DLH 1 /* divisor latch (msb) */
54 #define LCR 3 /* line control register */
55 #define MCR 4 /* modem control register */
56
59 #define B9600L 0X0c /* lsb bit pattern for 9600 baud */
60 #define B9600H 0X0 /* hsb bit pattern for 9600 baud */
61 #define DTR 0x01 /* Data Terminal Ready */
62 #define RTS 0x02 /* Request To Send */
63 #define STOP1 0x00 /* 1 stop bit */
64 #define BITS8 0x03 /* 8 bits per char */
65
66 #endif /* DEBUG */
67
68 /*
69 * This file contains the low level routines involved in getting
70 * into and out of ACPI S3, including those needed for restarting
71 * the non-boot cpus.
72 *
73 * Our assumptions:
74 *
75 * Our actions:
76 *
77 */
78
79 #if defined(lint) || defined(__lint)
80
81 /*ARGSUSED*/
82 int
83 wc_save_context(wc_cpu_t *pcpu)
84 { return 0; }
85
86 #else /* lint */
87
88 #if defined(__amd64)
89
90 ENTRY_NP(wc_save_context)
91
92 movq (%rsp), %rdx / return address
93 movq %rdx, WC_RETADDR(%rdi)
94 pushq %rbp
95 movq %rsp,%rbp
96
97 movq %rdi, WC_VIRTADDR(%rdi)
98 movq %rdi, WC_RDI(%rdi)
99
100 movq %rdx, WC_RDX(%rdi)
101
102 / stash everything else we need
103 sgdt WC_GDT(%rdi)
104 sidt WC_IDT(%rdi)
105 sldt WC_LDT(%rdi)
106 str WC_TR(%rdi)
107
108 movq %cr0, %rdx
109 movq %rdx, WC_CR0(%rdi)
157 movl %eax, WC_KGSBASE(%rdi)
158 movl %edx, WC_KGSBASE+4(%rdi)
159
160 movq %gs:CPU_ID, %rax / save current cpu id
161 movq %rax, WC_CPU_ID(%rdi)
162
163 pushfq
164 popq WC_EFLAGS(%rdi)
165
166 wbinvd / flush the cache
167 mfence
168
169 movq $1, %rax / at suspend return 1
170
171 leave
172
173 ret
174
175 SET_SIZE(wc_save_context)
176
177 #elif defined(__i386)
178
179 ENTRY_NP(wc_save_context)
180
181 movl 4(%esp), %eax / wc_cpu_t *
182 movl %eax, WC_VIRTADDR(%eax)
183
184 movl (%esp), %edx / return address
185 movl %edx, WC_RETADDR(%eax)
186
187 str WC_TR(%eax) / stash everything else we need
188 sgdt WC_GDT(%eax)
189 sldt WC_LDT(%eax)
190 sidt WC_IDT(%eax)
191
192 movl %cr0, %edx
193 movl %edx, WC_CR0(%eax)
194 movl %cr3, %edx
195 movl %edx, WC_CR3(%eax)
196 movl %cr4, %edx
197 movl %edx, WC_CR4(%eax)
198
199 movl %ebx, WC_EBX(%eax)
200 movl %edi, WC_EDI(%eax)
201 movl %esi, WC_ESI(%eax)
202 movl %ebp, WC_EBP(%eax)
203 movl %esp, WC_ESP(%eax)
204
205 movw %ss, WC_SS(%eax)
206 movw %cs, WC_CS(%eax)
207 movw %ds, WC_DS(%eax)
208 movw %es, WC_ES(%eax)
209 movw %fs, WC_FS(%eax)
210 movw %gs, WC_GS(%eax)
211
212 pushfl
213 popl WC_EFLAGS(%eax)
214
215 pushl %gs:CPU_ID / save current cpu id
216 popl WC_CPU_ID(%eax)
217
218 wbinvd / flush the cache
219 mfence
220
221 movl $1, %eax / at suspend return 1
222 ret
223
224 SET_SIZE(wc_save_context)
225
226 #endif /* __amd64 */
227
228 #endif /* lint */
229
230
231 /*
232 * Our assumptions:
233 * - We are running in real mode.
234 * - Interrupts are disabled.
235 *
236 * Our actions:
237 * - We start using our GDT by loading correct values in the
238 * selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL,
239 * gs=KGS_SEL).
240 * - We change over to using our IDT.
241 * - We load the default LDT into the hardware LDT register.
242 * - We load the default TSS into the hardware task register.
243 * - We restore registers
244 * - We return to original caller (a la setjmp)
245 */
246
247 #if defined(lint) || defined(__lint)
248
249 void
250 wc_rm_start(void)
251 {}
252
253 void
254 wc_rm_end(void)
255 {}
256
257 #else /* lint */
258
259 #if defined(__amd64)
260
261 ENTRY_NP(wc_rm_start)
262
263 /*
264 * For the Sun Studio 10 assembler we needed to do a .code32 and
265 * mentally invert the meaning of the addr16 and data16 prefixes to
266 * get 32-bit access when generating code to be executed in 16-bit
267 * mode (sigh...)
268 *
269 * This code, despite always being built with GNU as, has inherited
270 * the conceptual damage.
271 */
272
273 .code32
274
275 cli
276 movw %cs, %ax
277 movw %ax, %ds / establish ds ...
278 movw %ax, %ss / ... and ss:esp
279 D16 movl $WC_STKSTART, %esp
280 / using the following value blows up machines! - DO NOT USE
854 movq WC_RETADDR(%rax), %rax
855 movq %rax, (%rsp) / return to caller of wc_save_context
856
857 xorl %eax, %eax / at wakeup return 0
858 ret
859
860
861 SET_SIZE(wc_rm_start)
862
863 ENTRY_NP(asmspin)
864
865 movl %edi, %ecx
866 A1:
867 loop A1
868
869 SET_SIZE(asmspin)
870
871 .globl wc_rm_end
872 wc_rm_end:
873 nop
874
875 #elif defined(__i386)
876
877 ENTRY_NP(wc_rm_start)
878
879 /entry: jmp entry / stop here for HDT
880
881 cli
882 movw %cs, %ax
883 movw %ax, %ds / establish ds ...
884 movw %ax, %ss / ... and ss:esp
885 D16 movl $WC_STKSTART, %esp
886
887 #if LED
888 D16 movl $WC_LED, %edx
889 D16 movb $0xd1, %al
890 outb (%dx)
891 #endif
892
893 #if SERIAL
894 D16 movl $WC_COM, %edx
895 D16 movb $0x61, %al
896 outb (%dx)
897 #endif
898
899
900 D16 call vgainit
901 D16 call kbdinit
902 D16 call cominit
903
904 #if LED
905 D16 movl $WC_LED, %edx
906 D16 movb $0xd2, %al
907 outb (%dx)
908 #endif
909
910 #if SERIAL
911 D16 movl $WC_COM, %edx
912 D16 movb $0x62, %al
913 outb (%dx)
914 #endif
915
916 D16 A16 movl $WC_CPU, %ebx / base add of wc_cpu_t
917
918 #if LED
919 D16 movb $0xd3, %al
920 outb $WC_LED
921 #endif
922
923 #if SERIAL
924 D16 movl $WC_COM, %edx
925 D16 movb $0x63, %al
926 outb (%dx)
927 #endif
928
929 D16 A16 movl %cs:WC_DS(%ebx), %edx / %ds post prot/paging transit
930
931 #if LED
932 D16 movb $0xd4, %al
933 outb $WC_LED
934 #endif
935
936 D16 A16 lgdt %cs:WC_GDT(%ebx) / restore gdt and idtr
937 D16 A16 lidt %cs:WC_IDT(%ebx)
938
939 #if LED
940 D16 movb $0xd5, %al
941 outb $WC_LED
942 #endif
943
944 D16 A16 movl %cs:WC_CR4(%ebx), %eax / restore cr4
945 D16 andl $_BITNOT(CR4_PGE), %eax / don't set Global Enable yet
946 movl %eax, %cr4
947
948 #if LED
949 D16 movb $0xd6, %al
950 outb $WC_LED
951 #endif
952
953 D16 A16 movl %cs:WC_CR3(%ebx), %eax / set PDPT
954 movl %eax, %cr3
955
956 #if LED
957 D16 movb $0xd7, %al
958 outb $WC_LED
959 #endif
960
961 D16 A16 movl %cs:WC_CR0(%ebx), %eax / enable prot/paging, etc.
962 movl %eax, %cr0
963
964 #if LED
965 D16 movb $0xd8, %al
966 outb $WC_LED
967 #endif
968
969 D16 A16 movl %cs:WC_VIRTADDR(%ebx), %ebx / virtaddr of wc_cpu_t
970
971 #if LED
972 D16 movb $0xd9, %al
973 outb $WC_LED
974 #endif
975
976 #if LED
977 D16 movb $0xda, %al
978 outb $WC_LED
979 #endif
980
981 jmp flush / flush prefetch queue
982 flush:
983 D16 pushl $KCS_SEL
984 D16 pushl $kernel_wc_code
985 D16 lret / re-appear at kernel_wc_code
986
987
988 /*
989 * Support routine to re-initialize VGA subsystem
990 */
991 vgainit:
992 D16 ret
993
994 /*
995 * Support routine to re-initialize keyboard (which is USB - help!)
996 */
997 kbdinit:
998 D16 ret
999
1000 /*
1001 * Support routine to re-initialize COM ports to something sane for debug output
1002 */
1003 cominit:
1004 #if DEBUG
1005 /*
1006 * on debug kernels we need to initialize COM1 & COM2 here, so that
1007 * we can get debug output before the asy driver has resumed
1008 */
1009
1010 / select COM1
1011 D16 movl $_CONST(COM1+LCR), %edx
1012 D16 movb $DLAB, %al / divisor latch
1013 outb (%dx)
1014
1015 D16 movl $_CONST(COM1+DLL), %edx / divisor latch lsb
1016 D16 movb $B9600L, %al / divisor latch
1017 outb (%dx)
1018
1019 D16 movl $_CONST(COM1+DLH), %edx / divisor latch hsb
1020 D16 movb $B9600H, %al / divisor latch
1021 outb (%dx)
1022
1023 D16 movl $_CONST(COM1+LCR), %edx / select COM1
1024 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
1025 outb (%dx)
1026
1027 D16 movl $_CONST(COM1+MCR), %edx / select COM1
1028 D16 movb $_CONST(RTS|DTR), %al / 1 stop bit, 8bit word len
1029 outb (%dx)
1030
1031 / select COM2
1032 D16 movl $_CONST(COM2+LCR), %edx
1033 D16 movb $DLAB, %al / divisor latch
1034 outb (%dx)
1035
1036 D16 movl $_CONST(COM2+DLL), %edx / divisor latch lsb
1037 D16 movb $B9600L, %al / divisor latch
1038 outb (%dx)
1039
1040 D16 movl $_CONST(COM2+DLH), %edx / divisor latch hsb
1041 D16 movb $B9600H, %al / divisor latch
1042 outb (%dx)
1043
1044 D16 movl $_CONST(COM2+LCR), %edx / select COM1
1045 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
1046 outb (%dx)
1047
1048 D16 movl $_CONST(COM2+MCR), %edx / select COM1
1049 D16 movb $_CONST(RTS|DTR), %al / 1 stop bit, 8bit word len
1050 outb (%dx)
1051 #endif /* DEBUG */
1052
1053 D16 ret
1054
1055 .globl wc_rm_end
1056 wc_rm_end:
1057 nop
1058
1059 .globl kernel_wc_code
1060 kernel_wc_code:
1061 / At this point we are with kernel's cs and proper eip.
1062 / We will be executing not from the copy in real mode platter,
1063 / but from the original code where boot loaded us.
1064 / By this time GDT and IDT are loaded as is cr0, cr3 and cr4.
1065 / %ebx is wc_cpu
1066 / %dx is our ds
1067
1068 #if LED
1069 D16 movb $0xdb, %al
1070 outb $WC_LED
1071 #endif
1072
1073 / got here OK
1074
1075 movw %dx, %ds / $KDS_SEL
1076
1077 #if LED
1078 movb $0xdc, %al
1079 outb $WC_LED
1080 #endif
1081
1082 /*
1083 * Before proceeding, enable usage of the page table NX bit if
1084 * that's how the page tables are set up.
1085 */
1086 bt $X86FSET_NX, x86_featureset
1087 jnc 1f
1088 movl $MSR_AMD_EFER, %ecx
1089 rdmsr
1090 orl $AMD_EFER_NXE, %eax
1091 wrmsr
1092 1:
1093
1094 movl WC_CR4(%ebx), %eax / restore full cr4 (with Global Enable)
1095 movl %eax, %cr4
1096
1097
1098 lldt WC_LDT(%ebx) / $LDT_SEL
1099
1100 movzwl WC_TR(%ebx), %eax / clear TSS busy bit
1101 addl WC_GDT+2(%ebx), %eax
1102 andl $_BITNOT(0x200), 4(%eax)
1103 ltr WC_TR(%ebx) / $UTSS_SEL
1104
1105 movw WC_SS(%ebx), %ss / restore segment registers
1106 movw WC_ES(%ebx), %es
1107 movw WC_FS(%ebx), %fs
1108 movw WC_GS(%ebx), %gs
1109
1110 /*
1111 * set the stack pointer to point into the identity mapped page
1112 * temporarily, so we can make function calls
1113 */
1114 .globl rm_platter_va
1115 movl rm_platter_va, %eax
1116 movl $WC_STKSTART, %esp
1117 addl %eax, %esp
1118 movl %esp, %ebp
1119
1120 /*
1121 * if we are not running on the boot CPU restore stack contents by
1122 * calling i_cpr_restore_stack(curthread, save_stack);
1123 */
1124 call i_cpr_bootcpuid
1125 cmpl %eax, WC_CPU_ID(%ebx)
1126 je 2f
1127
1128 pushl WC_SAVED_STACK(%ebx)
1129 pushl %gs:CPU_THREAD
1130 call i_cpr_restore_stack
1131 addl $0x10, %esp
1132 2:
1133
1134 movl WC_ESP(%ebx), %esp
1135 movl %esp, %ebp
1136
1137 movl WC_RETADDR(%ebx), %eax / return to caller of wc_save_context
1138 movl %eax, (%esp)
1139
1140 /*
1141 * APIC initialization, skip iff function pointer is NULL
1142 */
1143 cmpl $0, ap_mlsetup
1144 je 3f
1145 call *ap_mlsetup
1146 3:
1147
1148 call *cpr_start_cpu_func
1149
1150 pushl WC_EFLAGS(%ebx) / restore flags
1151 popfl
1152
1153 movl WC_EDI(%ebx), %edi / restore general registers
1154 movl WC_ESI(%ebx), %esi
1155 movl WC_EBP(%ebx), %ebp
1156 movl WC_EBX(%ebx), %ebx
1157
1158 /exit: jmp exit / stop here for HDT
1159
1160 xorl %eax, %eax / at wakeup return 0
1161 ret
1162
1163 SET_SIZE(wc_rm_start)
1164
1165
1166 #endif /* defined(__amd64) */
1167
1168 #endif /* lint */
1169
|
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2019 Joyent, Inc.
24 */
25
26 #include <sys/asm_linkage.h>
27 #include <sys/asm_misc.h>
28 #include <sys/regset.h>
29 #include <sys/privregs.h>
30 #include <sys/x86_archext.h>
31 #include <sys/cpr_wakecode.h>
32
33 #include <sys/segments.h>
34 #include "assym.h"
35
36 #ifdef DEBUG
37 #define LED 1
38 #define SERIAL 1
39 #endif /* DEBUG */
40
41 #ifdef DEBUG
42 #define COM1 0x3f8
43 #define COM2 0x2f8
44 #define WC_COM COM2 /* either COM1 or COM2 */
45 #define WC_LED 0x80 /* diagnostic led port ON motherboard */
46
47 /*
48 * defined as offsets from the data register
49 */
50 #define DLL 0 /* divisor latch (lsb) */
51 #define DLH 1 /* divisor latch (msb) */
52 #define LCR 3 /* line control register */
53 #define MCR 4 /* modem control register */
54
57 #define B9600L 0X0c /* lsb bit pattern for 9600 baud */
58 #define B9600H 0X0 /* hsb bit pattern for 9600 baud */
59 #define DTR 0x01 /* Data Terminal Ready */
60 #define RTS 0x02 /* Request To Send */
61 #define STOP1 0x00 /* 1 stop bit */
62 #define BITS8 0x03 /* 8 bits per char */
63
64 #endif /* DEBUG */
65
66 /*
67 * This file contains the low level routines involved in getting
68 * into and out of ACPI S3, including those needed for restarting
69 * the non-boot cpus.
70 *
71 * Our assumptions:
72 *
73 * Our actions:
74 *
75 */
76
77 ENTRY_NP(wc_save_context)
78
79 movq (%rsp), %rdx / return address
80 movq %rdx, WC_RETADDR(%rdi)
81 pushq %rbp
82 movq %rsp,%rbp
83
84 movq %rdi, WC_VIRTADDR(%rdi)
85 movq %rdi, WC_RDI(%rdi)
86
87 movq %rdx, WC_RDX(%rdi)
88
89 / stash everything else we need
90 sgdt WC_GDT(%rdi)
91 sidt WC_IDT(%rdi)
92 sldt WC_LDT(%rdi)
93 str WC_TR(%rdi)
94
95 movq %cr0, %rdx
96 movq %rdx, WC_CR0(%rdi)
144 movl %eax, WC_KGSBASE(%rdi)
145 movl %edx, WC_KGSBASE+4(%rdi)
146
147 movq %gs:CPU_ID, %rax / save current cpu id
148 movq %rax, WC_CPU_ID(%rdi)
149
150 pushfq
151 popq WC_EFLAGS(%rdi)
152
153 wbinvd / flush the cache
154 mfence
155
156 movq $1, %rax / at suspend return 1
157
158 leave
159
160 ret
161
162 SET_SIZE(wc_save_context)
163
164
165 /*
166 * Our assumptions:
167 * - We are running in real mode.
168 * - Interrupts are disabled.
169 *
170 * Our actions:
171 * - We start using our GDT by loading correct values in the
172 * selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL,
173 * gs=KGS_SEL).
174 * - We change over to using our IDT.
175 * - We load the default LDT into the hardware LDT register.
176 * - We load the default TSS into the hardware task register.
177 * - We restore registers
178 * - We return to original caller (a la setjmp)
179 */
180
181 ENTRY_NP(wc_rm_start)
182
183 /*
184 * For the Sun Studio 10 assembler we needed to do a .code32 and
185 * mentally invert the meaning of the addr16 and data16 prefixes to
186 * get 32-bit access when generating code to be executed in 16-bit
187 * mode (sigh...)
188 *
189 * This code, despite always being built with GNU as, has inherited
190 * the conceptual damage.
191 */
192
193 .code32
194
195 cli
196 movw %cs, %ax
197 movw %ax, %ds / establish ds ...
198 movw %ax, %ss / ... and ss:esp
199 D16 movl $WC_STKSTART, %esp
200 / using the following value blows up machines! - DO NOT USE
774 movq WC_RETADDR(%rax), %rax
775 movq %rax, (%rsp) / return to caller of wc_save_context
776
777 xorl %eax, %eax / at wakeup return 0
778 ret
779
780
781 SET_SIZE(wc_rm_start)
782
783 ENTRY_NP(asmspin)
784
785 movl %edi, %ecx
786 A1:
787 loop A1
788
789 SET_SIZE(asmspin)
790
791 .globl wc_rm_end
792 wc_rm_end:
793 nop
794
|