Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / i86pc / ml / cpr_wakecode.s
blobc52f01e60bb9a51eb8909a6cd6bc682546bd81a5
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/asm_linkage.h>
26 #include <sys/asm_misc.h>
27 #include <sys/regset.h>
28 #include <sys/privregs.h>
29 #include <sys/x86_archext.h>
30 #include <sys/cpr_wakecode.h>
32 #include <sys/segments.h>
33 #include "assym.h"
35 #ifdef DEBUG
36 #define LED 1
37 #define SERIAL 1
38 #endif /* DEBUG */
40 #ifdef DEBUG
41 #define COM1 0x3f8
42 #define COM2 0x2f8
43 #define WC_COM COM2 /* either COM1 or COM2 */
44 #define WC_LED 0x80 /* diagnostic led port ON motherboard */
47 * defined as offsets from the data register
49 #define DLL 0 /* divisor latch (lsb) */
50 #define DLH 1 /* divisor latch (msb) */
51 #define LCR 3 /* line control register */
52 #define MCR 4 /* modem control register */
55 #define DLAB 0x80 /* divisor latch access bit */
56 #define B9600L 0X0c /* lsb bit pattern for 9600 baud */
57 #define B9600H 0X0 /* hsb bit pattern for 9600 baud */
58 #define DTR 0x01 /* Data Terminal Ready */
59 #define RTS 0x02 /* Request To Send */
60 #define STOP1 0x00 /* 1 stop bit */
61 #define BITS8 0x03 /* 8 bits per char */
63 #endif /* DEBUG */
66 * This file contains the low level routines involved in getting
67 * into and out of ACPI S3, including those needed for restarting
68 * the non-boot cpus.
70 * Our assumptions:
72 * Our actions:
77 #if defined(__amd64)
79 ENTRY_NP(wc_save_context)
81 movq (%rsp), %rdx / return address
82 movq %rdx, WC_RETADDR(%rdi)
83 pushq %rbp
84 movq %rsp,%rbp
86 movq %rdi, WC_VIRTADDR(%rdi)
87 movq %rdi, WC_RDI(%rdi)
89 movq %rdx, WC_RDX(%rdi)
91 / stash everything else we need
92 sgdt WC_GDT(%rdi)
93 sidt WC_IDT(%rdi)
94 sldt WC_LDT(%rdi)
95 str WC_TR(%rdi)
97 movq %cr0, %rdx
98 movq %rdx, WC_CR0(%rdi)
99 movq %cr3, %rdx
100 movq %rdx, WC_CR3(%rdi)
101 movq %cr4, %rdx
102 movq %rdx, WC_CR4(%rdi)
103 movq %cr8, %rdx
104 movq %rdx, WC_CR8(%rdi)
106 movq %r8, WC_R8(%rdi)
107 movq %r9, WC_R9(%rdi)
108 movq %r10, WC_R10(%rdi)
109 movq %r11, WC_R11(%rdi)
110 movq %r12, WC_R12(%rdi)
111 movq %r13, WC_R13(%rdi)
112 movq %r14, WC_R14(%rdi)
113 movq %r15, WC_R15(%rdi)
114 movq %rax, WC_RAX(%rdi)
115 movq %rbp, WC_RBP(%rdi)
116 movq %rbx, WC_RBX(%rdi)
117 movq %rcx, WC_RCX(%rdi)
118 movq %rsi, WC_RSI(%rdi)
119 movq %rsp, WC_RSP(%rdi)
121 movw %ss, WC_SS(%rdi)
122 movw %cs, WC_CS(%rdi)
123 movw %ds, WC_DS(%rdi)
124 movw %es, WC_ES(%rdi)
126 movq $0, %rcx / save %fs register
127 movw %fs, %cx
128 movq %rcx, WC_FS(%rdi)
130 movl $MSR_AMD_FSBASE, %ecx
131 rdmsr
132 movl %eax, WC_FSBASE(%rdi)
133 movl %edx, WC_FSBASE+4(%rdi)
135 movq $0, %rcx / save %gs register
136 movw %gs, %cx
137 movq %rcx, WC_GS(%rdi)
139 movl $MSR_AMD_GSBASE, %ecx / save gsbase msr
140 rdmsr
141 movl %eax, WC_GSBASE(%rdi)
142 movl %edx, WC_GSBASE+4(%rdi)
144 movl $MSR_AMD_KGSBASE, %ecx / save kgsbase msr
145 rdmsr
146 movl %eax, WC_KGSBASE(%rdi)
147 movl %edx, WC_KGSBASE+4(%rdi)
149 movq %gs:CPU_ID, %rax / save current cpu id
150 movq %rax, WC_CPU_ID(%rdi)
152 pushfq
153 popq WC_EFLAGS(%rdi)
155 wbinvd / flush the cache
156 mfence
158 movq $1, %rax / at suspend return 1
160 leave
164 SET_SIZE(wc_save_context)
166 #elif defined(__i386)
168 ENTRY_NP(wc_save_context)
170 movl 4(%esp), %eax / wc_cpu_t *
171 movl %eax, WC_VIRTADDR(%eax)
173 movl (%esp), %edx / return address
174 movl %edx, WC_RETADDR(%eax)
176 str WC_TR(%eax) / stash everything else we need
177 sgdt WC_GDT(%eax)
178 sldt WC_LDT(%eax)
179 sidt WC_IDT(%eax)
181 movl %cr0, %edx
182 movl %edx, WC_CR0(%eax)
183 movl %cr3, %edx
184 movl %edx, WC_CR3(%eax)
185 movl %cr4, %edx
186 movl %edx, WC_CR4(%eax)
188 movl %ebx, WC_EBX(%eax)
189 movl %edi, WC_EDI(%eax)
190 movl %esi, WC_ESI(%eax)
191 movl %ebp, WC_EBP(%eax)
192 movl %esp, WC_ESP(%eax)
194 movw %ss, WC_SS(%eax)
195 movw %cs, WC_CS(%eax)
196 movw %ds, WC_DS(%eax)
197 movw %es, WC_ES(%eax)
198 movw %fs, WC_FS(%eax)
199 movw %gs, WC_GS(%eax)
201 pushfl
202 popl WC_EFLAGS(%eax)
204 pushl %gs:CPU_ID / save current cpu id
205 popl WC_CPU_ID(%eax)
207 wbinvd / flush the cache
208 mfence
210 movl $1, %eax / at suspend return 1
213 SET_SIZE(wc_save_context)
215 #endif /* __amd64 */
220 * Our assumptions:
221 * - We are running in real mode.
222 * - Interrupts are disabled.
224 * Our actions:
225 * - We start using our GDT by loading correct values in the
226 * selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL,
227 * gs=KGS_SEL).
228 * - We change over to using our IDT.
229 * - We load the default LDT into the hardware LDT register.
230 * - We load the default TSS into the hardware task register.
231 * - We restore registers
232 * - We return to original caller (a la setjmp)
236 #if defined(__amd64)
238 ENTRY_NP(wc_rm_start)
241 * For the Sun Studio 10 assembler we needed to do a .code32 and
242 * mentally invert the meaning of the addr16 and data16 prefixes to
243 * get 32-bit access when generating code to be executed in 16-bit
244 * mode (sigh...)
246 * This code, despite always being built with GNU as, has inherited
247 * the conceptual damage.
250 .code32
253 movw %cs, %ax
254 movw %ax, %ds / establish ds ...
255 movw %ax, %ss / ... and ss:esp
256 D16 movl $WC_STKSTART, %esp
257 / using the following value blows up machines! - DO NOT USE
258 / D16 movl 0xffc, %esp
261 #if LED
262 D16 movl $WC_LED, %edx
263 D16 movb $0xd1, %al
264 outb (%dx)
265 #endif
267 #if SERIAL
268 D16 movl $WC_COM, %edx
269 D16 movb $0x61, %al
270 outb (%dx)
271 #endif
273 D16 call cominit
276 * Enable protected-mode, write protect, and alignment mask
277 * %cr0 has already been initialsed to zero
279 movl %cr0, %eax
280 D16 orl $_CONST(CR0_PE|CR0_WP|CR0_AM), %eax
281 movl %eax, %cr0
284 * Do a jmp immediately after writing to cr0 when enabling protected
285 * mode to clear the real mode prefetch queue (per Intel's docs)
287 jmp pestart
288 pestart:
290 #if LED
291 D16 movl $WC_LED, %edx
292 D16 movb $0xd2, %al
293 outb (%dx)
294 #endif
296 #if SERIAL
297 D16 movl $WC_COM, %edx
298 D16 movb $0x62, %al
299 outb (%dx)
300 #endif
303 * 16-bit protected mode is now active, so prepare to turn on long
304 * mode
307 #if LED
308 D16 movl $WC_LED, %edx
309 D16 movb $0xd3, %al
310 outb (%dx)
311 #endif
313 #if SERIAL
314 D16 movl $WC_COM, %edx
315 D16 movb $0x63, %al
316 outb (%dx)
317 #endif
320 * Add any initial cr4 bits
322 movl %cr4, %eax
323 A16 D16 orl CR4OFF, %eax
326 * Enable PAE mode (CR4.PAE)
328 D16 orl $CR4_PAE, %eax
329 movl %eax, %cr4
331 #if LED
332 D16 movl $WC_LED, %edx
333 D16 movb $0xd4, %al
334 outb (%dx)
335 #endif
337 #if SERIAL
338 D16 movl $WC_COM, %edx
339 D16 movb $0x64, %al
340 outb (%dx)
341 #endif
344 * Point cr3 to the 64-bit long mode page tables.
346 * Note that these MUST exist in 32-bit space, as we don't have
347 * a way to load %cr3 with a 64-bit base address for the page tables
348 * until the CPU is actually executing in 64-bit long mode.
350 A16 D16 movl CR3OFF, %eax
351 movl %eax, %cr3
354 * Set long mode enable in EFER (EFER.LME = 1)
356 D16 movl $MSR_AMD_EFER, %ecx
357 rdmsr
359 D16 orl $AMD_EFER_LME, %eax
360 wrmsr
362 #if LED
363 D16 movl $WC_LED, %edx
364 D16 movb $0xd5, %al
365 outb (%dx)
366 #endif
368 #if SERIAL
369 D16 movl $WC_COM, %edx
370 D16 movb $0x65, %al
371 outb (%dx)
372 #endif
375 * Finally, turn on paging (CR0.PG = 1) to activate long mode.
377 movl %cr0, %eax
378 D16 orl $CR0_PG, %eax
379 movl %eax, %cr0
382 * The instruction after enabling paging in CR0 MUST be a branch.
384 jmp long_mode_active
386 long_mode_active:
388 #if LED
389 D16 movl $WC_LED, %edx
390 D16 movb $0xd6, %al
391 outb (%dx)
392 #endif
394 #if SERIAL
395 D16 movl $WC_COM, %edx
396 D16 movb $0x66, %al
397 outb (%dx)
398 #endif
401 * Long mode is now active but since we're still running with the
402 * original 16-bit CS we're actually in 16-bit compatability mode.
404 * We have to load an intermediate GDT and IDT here that we know are
405 * in 32-bit space before we can use the kernel's GDT and IDT, which
406 * may be in the 64-bit address space, and since we're in compatability
407 * mode, we only have access to 16 and 32-bit instructions at the
408 * moment.
410 A16 D16 lgdt TEMPGDTOFF /* load temporary GDT */
411 A16 D16 lidt TEMPIDTOFF /* load temporary IDT */
415 * Do a far transfer to 64-bit mode. Set the CS selector to a 64-bit
416 * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump
417 * to the real mode platter address of wc_long_mode_64 as until the
418 * 64-bit CS is in place we don't have access to 64-bit instructions
419 * and thus can't reference a 64-bit %rip.
422 #if LED
423 D16 movl $WC_LED, %edx
424 D16 movb $0xd7, %al
425 outb (%dx)
426 #endif
428 #if SERIAL
429 D16 movl $WC_COM, %edx
430 D16 movb $0x67, %al
431 outb (%dx)
432 #endif
434 D16 pushl $TEMP_CS64_SEL
435 A16 D16 pushl LM64OFF
437 D16 lret
441 * Support routine to re-initialize VGA subsystem
443 vgainit:
444 D16 ret
447 * Support routine to re-initialize keyboard (which is USB - help!)
449 kbdinit:
450 D16 ret
453 * Support routine to re-initialize COM ports to something sane
455 cominit:
456 / init COM1 & COM2
458 #if DEBUG
460 * on debug kernels we need to initialize COM1 & COM2 here, so that
461 * we can get debug output before the asy driver has resumed
464 / select COM1
465 D16 movl $_CONST(COM1+LCR), %edx
466 D16 movb $DLAB, %al / divisor latch
467 outb (%dx)
469 D16 movl $_CONST(COM1+DLL), %edx / divisor latch lsb
470 D16 movb $B9600L, %al / divisor latch
471 outb (%dx)
473 D16 movl $_CONST(COM1+DLH), %edx / divisor latch hsb
474 D16 movb $B9600H, %al / divisor latch
475 outb (%dx)
477 D16 movl $_CONST(COM1+LCR), %edx / select COM1
478 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
479 outb (%dx)
481 D16 movl $_CONST(COM1+MCR), %edx / select COM1
482 D16 movb $_CONST(RTS|DTR), %al / data term ready & req to send
483 outb (%dx)
485 / select COM2
486 D16 movl $_CONST(COM2+LCR), %edx
487 D16 movb $DLAB, %al / divisor latch
488 outb (%dx)
490 D16 movl $_CONST(COM2+DLL), %edx / divisor latch lsb
491 D16 movb $B9600L, %al / divisor latch
492 outb (%dx)
494 D16 movl $_CONST(COM2+DLH), %edx / divisor latch hsb
495 D16 movb $B9600H, %al / divisor latch
496 outb (%dx)
498 D16 movl $_CONST(COM2+LCR), %edx / select COM1
499 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
500 outb (%dx)
502 D16 movl $_CONST(COM2+MCR), %edx / select COM1
503 D16 movb $_CONST(RTS|DTR), %al / data term ready & req to send
504 outb (%dx)
505 #endif /* DEBUG */
507 D16 ret
509 .code64
511 .globl wc_long_mode_64
512 wc_long_mode_64:
514 #if LED
515 movw $WC_LED, %dx
516 movb $0xd8, %al
517 outb (%dx)
518 #endif
520 #if SERIAL
521 movw $WC_COM, %dx
522 movb $0x68, %al
523 outb (%dx)
524 #endif
527 * We are now running in long mode with a 64-bit CS (EFER.LMA=1,
528 * CS.L=1) so we now have access to 64-bit instructions.
530 * First, set the 64-bit GDT base.
532 .globl rm_platter_pa
533 movl rm_platter_pa, %eax
535 lgdtq GDTROFF(%rax) /* load 64-bit GDT */
538 * Save the CPU number in %r11; get the value here since it's saved in
539 * the real mode platter.
541 / JAN
542 / the following is wrong! need to figure out MP systems
543 / movl CPUNOFF(%rax), %r11d
546 * Add rm_platter_pa to %rsp to point it to the same location as seen
547 * from 64-bit mode.
549 addq %rax, %rsp
552 * Now do an lretq to load CS with the appropriate selector for the
553 * kernel's 64-bit GDT and to start executing 64-bit setup code at the
554 * virtual address where boot originally loaded this code rather than
555 * the copy in the real mode platter's rm_code array as we've been
556 * doing so far.
559 #if LED
560 movw $WC_LED, %dx
561 movb $0xd9, %al
562 outb (%dx)
563 #endif
565 / JAN this should produce 'i' but we get 'g' instead ???
566 #if SERIAL
567 movw $WC_COM, %dx
568 movb $0x69, %al
569 outb (%dx)
570 #endif
572 pushq $KCS_SEL
573 pushq $kernel_wc_code
574 lretq
576 .globl kernel_wc_code
577 kernel_wc_code:
579 #if LED
580 movw $WC_LED, %dx
581 movb $0xda, %al
582 outb (%dx)
583 #endif
585 / JAN this should produce 'j' but we get 'g' instead ???
586 #if SERIAL
587 movw $WC_COM, %dx
588 movb $0x6a, %al
589 outb (%dx)
590 #endif
593 * Complete the balance of the setup we need to before executing
594 * 64-bit kernel code (namely init rsp, TSS, LGDT, FS and GS).
596 .globl rm_platter_va
597 movq rm_platter_va, %rbx
598 addq $WC_CPU, %rbx
600 #if LED
601 movw $WC_LED, %dx
602 movb $0xdb, %al
603 outb (%dx)
604 #endif
606 #if SERIAL
607 movw $WC_COM, %dx
608 movw $0x6b, %ax
609 outb (%dx)
610 #endif
613 * restore the rest of the registers
616 lidtq WC_IDT(%rbx)
618 #if LED
619 movw $WC_LED, %dx
620 movb $0xdc, %al
621 outb (%dx)
622 #endif
624 #if SERIAL
625 movw $WC_COM, %dx
626 movw $0x6c, %ax
627 outb (%dx)
628 #endif
631 * restore the rest of the registers
634 movw $KDS_SEL, %ax
635 movw %ax, %ds
636 movw %ax, %es
637 movw %ax, %ss
640 * Before proceeding, enable usage of the page table NX bit if
641 * that's how the page tables are set up.
643 bt $X86FSET_NX, x86_featureset(%rip)
644 jnc 1f
645 movl $MSR_AMD_EFER, %ecx
646 rdmsr
647 orl $AMD_EFER_NXE, %eax
648 wrmsr
651 movq WC_CR4(%rbx), %rax / restore full cr4 (with Global Enable)
652 movq %rax, %cr4
654 lldt WC_LDT(%rbx)
655 movzwq WC_TR(%rbx), %rax / clear TSS busy bit
656 addq WC_GDT+2(%rbx), %rax
657 andl $0xfffffdff, 4(%rax)
658 movq 4(%rax), %rcx
659 ltr WC_TR(%rbx)
661 #if LED
662 movw $WC_LED, %dx
663 movb $0xdd, %al
664 outb (%dx)
665 #endif
667 #if SERIAL
668 movw $WC_COM, %dx
669 movw $0x6d, %ax
670 outb (%dx)
671 #endif
673 / restore %fsbase %gsbase %kgbase registers using wrmsr instruction
675 movq WC_FS(%rbx), %rcx / restore fs register
676 movw %cx, %fs
678 movl $MSR_AMD_FSBASE, %ecx
679 movl WC_FSBASE(%rbx), %eax
680 movl WC_FSBASE+4(%rbx), %edx
681 wrmsr
683 movq WC_GS(%rbx), %rcx / restore gs register
684 movw %cx, %gs
686 movl $MSR_AMD_GSBASE, %ecx / restore gsbase msr
687 movl WC_GSBASE(%rbx), %eax
688 movl WC_GSBASE+4(%rbx), %edx
689 wrmsr
691 movl $MSR_AMD_KGSBASE, %ecx / restore kgsbase msr
692 movl WC_KGSBASE(%rbx), %eax
693 movl WC_KGSBASE+4(%rbx), %edx
694 wrmsr
696 movq WC_CR0(%rbx), %rdx
697 movq %rdx, %cr0
698 movq WC_CR3(%rbx), %rdx
699 movq %rdx, %cr3
700 movq WC_CR8(%rbx), %rdx
701 movq %rdx, %cr8
703 #if LED
704 movw $WC_LED, %dx
705 movb $0xde, %al
706 outb (%dx)
707 #endif
709 #if SERIAL
710 movw $WC_COM, %dx
711 movb $0x6e, %al
712 outb (%dx)
713 #endif
716 * if we are not running on the boot CPU restore stack contents by
717 * calling i_cpr_restore_stack(curthread, save_stack);
719 movq %rsp, %rbp
720 call i_cpr_bootcpuid
721 cmpl %eax, WC_CPU_ID(%rbx)
722 je 2f
724 movq %gs:CPU_THREAD, %rdi
725 movq WC_SAVED_STACK(%rbx), %rsi
726 call i_cpr_restore_stack
729 movq WC_RSP(%rbx), %rsp / restore stack pointer
732 * APIC initialization
734 movq %rsp, %rbp
737 * skip iff function pointer is NULL
739 cmpq $0, ap_mlsetup
740 je 3f
741 call *ap_mlsetup
744 call *cpr_start_cpu_func
746 / restore %rbx to the value it ahd before we called the functions above
747 movq rm_platter_va, %rbx
748 addq $WC_CPU, %rbx
750 movq WC_R8(%rbx), %r8
751 movq WC_R9(%rbx), %r9
752 movq WC_R10(%rbx), %r10
753 movq WC_R11(%rbx), %r11
754 movq WC_R12(%rbx), %r12
755 movq WC_R13(%rbx), %r13
756 movq WC_R14(%rbx), %r14
757 movq WC_R15(%rbx), %r15
758 / movq WC_RAX(%rbx), %rax
759 movq WC_RBP(%rbx), %rbp
760 movq WC_RCX(%rbx), %rcx
761 / movq WC_RDX(%rbx), %rdx
762 movq WC_RDI(%rbx), %rdi
763 movq WC_RSI(%rbx), %rsi
766 / assume that %cs does not need to be restored
767 / %ds, %es & %ss are ignored in 64bit mode
768 movw WC_SS(%rbx), %ss
769 movw WC_DS(%rbx), %ds
770 movw WC_ES(%rbx), %es
772 #if LED
773 movw $WC_LED, %dx
774 movb $0xdf, %al
775 outb (%dx)
776 #endif
778 #if SERIAL
779 movw $WC_COM, %dx
780 movb $0x6f, %al
781 outb (%dx)
782 #endif
785 movq WC_RBP(%rbx), %rbp
786 movq WC_RSP(%rbx), %rsp
788 #if LED
789 movw $WC_LED, %dx
790 movb $0xe0, %al
791 outb (%dx)
792 #endif
794 #if SERIAL
795 movw $WC_COM, %dx
796 movb $0x70, %al
797 outb (%dx)
798 #endif
801 movq WC_RCX(%rbx), %rcx
803 pushq WC_EFLAGS(%rbx) / restore flags
804 popfq
806 #if LED
807 movw $WC_LED, %dx
808 movb $0xe1, %al
809 outb (%dx)
810 #endif
812 #if SERIAL
813 movw $WC_COM, %dx
814 movb $0x71, %al
815 outb (%dx)
816 #endif
819 * can not use outb after this point, because doing so would mean using
820 * %dx which would modify %rdx which is restored here
823 movq %rbx, %rax
824 movq WC_RDX(%rax), %rdx
825 movq WC_RBX(%rax), %rbx
827 leave
829 movq WC_RETADDR(%rax), %rax
830 movq %rax, (%rsp) / return to caller of wc_save_context
832 xorl %eax, %eax / at wakeup return 0
836 SET_SIZE(wc_rm_start)
838 ENTRY_NP(asmspin)
840 movl %edi, %ecx
842 loop A1
844 SET_SIZE(asmspin)
846 .globl wc_rm_end
847 wc_rm_end:
850 #elif defined(__i386)
852 ENTRY_NP(wc_rm_start)
854 /entry: jmp entry / stop here for HDT
857 movw %cs, %ax
858 movw %ax, %ds / establish ds ...
859 movw %ax, %ss / ... and ss:esp
860 D16 movl $WC_STKSTART, %esp
862 #if LED
863 D16 movl $WC_LED, %edx
864 D16 movb $0xd1, %al
865 outb (%dx)
866 #endif
868 #if SERIAL
869 D16 movl $WC_COM, %edx
870 D16 movb $0x61, %al
871 outb (%dx)
872 #endif
875 D16 call vgainit
876 D16 call kbdinit
877 D16 call cominit
879 #if LED
880 D16 movl $WC_LED, %edx
881 D16 movb $0xd2, %al
882 outb (%dx)
883 #endif
885 #if SERIAL
886 D16 movl $WC_COM, %edx
887 D16 movb $0x62, %al
888 outb (%dx)
889 #endif
891 D16 A16 movl $WC_CPU, %ebx / base add of wc_cpu_t
893 #if LED
894 D16 movb $0xd3, %al
895 outb $WC_LED
896 #endif
898 #if SERIAL
899 D16 movl $WC_COM, %edx
900 D16 movb $0x63, %al
901 outb (%dx)
902 #endif
904 D16 A16 movl %cs:WC_DS(%ebx), %edx / %ds post prot/paging transit
906 #if LED
907 D16 movb $0xd4, %al
908 outb $WC_LED
909 #endif
911 D16 A16 lgdt %cs:WC_GDT(%ebx) / restore gdt and idtr
912 D16 A16 lidt %cs:WC_IDT(%ebx)
914 #if LED
915 D16 movb $0xd5, %al
916 outb $WC_LED
917 #endif
919 D16 A16 movl %cs:WC_CR4(%ebx), %eax / restore cr4
920 D16 andl $_BITNOT(CR4_PGE), %eax / don't set Global Enable yet
921 movl %eax, %cr4
923 #if LED
924 D16 movb $0xd6, %al
925 outb $WC_LED
926 #endif
928 D16 A16 movl %cs:WC_CR3(%ebx), %eax / set PDPT
929 movl %eax, %cr3
931 #if LED
932 D16 movb $0xd7, %al
933 outb $WC_LED
934 #endif
936 D16 A16 movl %cs:WC_CR0(%ebx), %eax / enable prot/paging, etc.
937 movl %eax, %cr0
939 #if LED
940 D16 movb $0xd8, %al
941 outb $WC_LED
942 #endif
944 D16 A16 movl %cs:WC_VIRTADDR(%ebx), %ebx / virtaddr of wc_cpu_t
946 #if LED
947 D16 movb $0xd9, %al
948 outb $WC_LED
949 #endif
951 #if LED
952 D16 movb $0xda, %al
953 outb $WC_LED
954 #endif
956 jmp flush / flush prefetch queue
957 flush:
958 D16 pushl $KCS_SEL
959 D16 pushl $kernel_wc_code
960 D16 lret / re-appear at kernel_wc_code
964 * Support routine to re-initialize VGA subsystem
966 vgainit:
967 D16 ret
970 * Support routine to re-initialize keyboard (which is USB - help!)
972 kbdinit:
973 D16 ret
976 * Support routine to re-initialize COM ports to something sane for debug output
978 cominit:
979 #if DEBUG
981 * on debug kernels we need to initialize COM1 & COM2 here, so that
982 * we can get debug output before the asy driver has resumed
985 / select COM1
986 D16 movl $_CONST(COM1+LCR), %edx
987 D16 movb $DLAB, %al / divisor latch
988 outb (%dx)
990 D16 movl $_CONST(COM1+DLL), %edx / divisor latch lsb
991 D16 movb $B9600L, %al / divisor latch
992 outb (%dx)
994 D16 movl $_CONST(COM1+DLH), %edx / divisor latch hsb
995 D16 movb $B9600H, %al / divisor latch
996 outb (%dx)
998 D16 movl $_CONST(COM1+LCR), %edx / select COM1
999 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
1000 outb (%dx)
1002 D16 movl $_CONST(COM1+MCR), %edx / select COM1
1003 D16 movb $_CONST(RTS|DTR), %al / 1 stop bit, 8bit word len
1004 outb (%dx)
1006 / select COM2
1007 D16 movl $_CONST(COM2+LCR), %edx
1008 D16 movb $DLAB, %al / divisor latch
1009 outb (%dx)
1011 D16 movl $_CONST(COM2+DLL), %edx / divisor latch lsb
1012 D16 movb $B9600L, %al / divisor latch
1013 outb (%dx)
1015 D16 movl $_CONST(COM2+DLH), %edx / divisor latch hsb
1016 D16 movb $B9600H, %al / divisor latch
1017 outb (%dx)
1019 D16 movl $_CONST(COM2+LCR), %edx / select COM1
1020 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
1021 outb (%dx)
1023 D16 movl $_CONST(COM2+MCR), %edx / select COM1
1024 D16 movb $_CONST(RTS|DTR), %al / 1 stop bit, 8bit word len
1025 outb (%dx)
1026 #endif /* DEBUG */
1028 D16 ret
1030 .globl wc_rm_end
1031 wc_rm_end:
1034 .globl kernel_wc_code
1035 kernel_wc_code:
1036 / At this point we are with kernel's cs and proper eip.
1037 / We will be executing not from the copy in real mode platter,
1038 / but from the original code where boot loaded us.
1039 / By this time GDT and IDT are loaded as is cr0, cr3 and cr4.
1040 / %ebx is wc_cpu
1041 / %dx is our ds
1043 #if LED
1044 D16 movb $0xdb, %al
1045 outb $WC_LED
1046 #endif
1048 / got here OK
1050 movw %dx, %ds / $KDS_SEL
1052 #if LED
1053 movb $0xdc, %al
1054 outb $WC_LED
1055 #endif
1058 * Before proceeding, enable usage of the page table NX bit if
1059 * that's how the page tables are set up.
1061 bt $X86FSET_NX, x86_featureset
1062 jnc 1f
1063 movl $MSR_AMD_EFER, %ecx
1064 rdmsr
1065 orl $AMD_EFER_NXE, %eax
1066 wrmsr
1069 movl WC_CR4(%ebx), %eax / restore full cr4 (with Global Enable)
1070 movl %eax, %cr4
1073 lldt WC_LDT(%ebx) / $LDT_SEL
1075 movzwl WC_TR(%ebx), %eax / clear TSS busy bit
1076 addl WC_GDT+2(%ebx), %eax
1077 andl $_BITNOT(0x200), 4(%eax)
1078 ltr WC_TR(%ebx) / $UTSS_SEL
1080 movw WC_SS(%ebx), %ss / restore segment registers
1081 movw WC_ES(%ebx), %es
1082 movw WC_FS(%ebx), %fs
1083 movw WC_GS(%ebx), %gs
1086 * set the stack pointer to point into the identity mapped page
1087 * temporarily, so we can make function calls
1089 .globl rm_platter_va
1090 movl rm_platter_va, %eax
1091 movl $WC_STKSTART, %esp
1092 addl %eax, %esp
1093 movl %esp, %ebp
1096 * if we are not running on the boot CPU restore stack contents by
1097 * calling i_cpr_restore_stack(curthread, save_stack);
1099 call i_cpr_bootcpuid
1100 cmpl %eax, WC_CPU_ID(%ebx)
1101 je 2f
1103 pushl WC_SAVED_STACK(%ebx)
1104 pushl %gs:CPU_THREAD
1105 call i_cpr_restore_stack
1106 addl $0x10, %esp
1109 movl WC_ESP(%ebx), %esp
1110 movl %esp, %ebp
1112 movl WC_RETADDR(%ebx), %eax / return to caller of wc_save_context
1113 movl %eax, (%esp)
1116 * APIC initialization, skip iff function pointer is NULL
1118 cmpl $0, ap_mlsetup
1119 je 3f
1120 call *ap_mlsetup
1123 call *cpr_start_cpu_func
1125 pushl WC_EFLAGS(%ebx) / restore flags
1126 popfl
1128 movl WC_EDI(%ebx), %edi / restore general registers
1129 movl WC_ESI(%ebx), %esi
1130 movl WC_EBP(%ebx), %ebp
1131 movl WC_EBX(%ebx), %ebx
1133 /exit: jmp exit / stop here for HDT
1135 xorl %eax, %eax / at wakeup return 0
1138 SET_SIZE(wc_rm_start)
1141 #endif /* defined(__amd64) */