summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2006-06-10 08:20:03 +0000
committernjl <njl@FreeBSD.org>2006-06-10 08:20:03 +0000
commit66b0070261edf8213d0517b7a31e3e4bf28f2fe3 (patch)
tree91f52fdd204b24111f29ecd6807eb88f5ed48c85 /sys/i386
parent00c07c39910ef7f9f06adf874feb0470efa94dd6 (diff)
downloadFreeBSD-src-66b0070261edf8213d0517b7a31e3e4bf28f2fe3.zip
FreeBSD-src-66b0070261edf8213d0517b7a31e3e4bf28f2fe3.tar.gz
Minor tweaks to the resume code. Previous commit reverted alignment back
to 4. There is no need to be more strict at assembly time since we copy the code anyway to a private page. * Clear the direction flag and eflags. Probably not necessary but it won't hurt to be safe. * Add prefixes to all instructions to prevent any assembler mistakes. * Remove zeroing of eax - edi. We use those registers immediately after to transfer values to protected mode so this was pointless. * Update comments to reflect info found during code review.
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/acpica/acpi_wakecode.S91
1 files changed, 50 insertions, 41 deletions
diff --git a/sys/i386/acpica/acpi_wakecode.S b/sys/i386/acpica/acpi_wakecode.S
index e8033e8..889a58a 100644
--- a/sys/i386/acpica/acpi_wakecode.S
+++ b/sys/i386/acpica/acpi_wakecode.S
@@ -34,20 +34,30 @@
#include "assym.s"
+/*
+ * Resume entry point. The BIOS enters here in real mode after POST with
+ * CS set to the page where we stored this code. It should configure the
+ * segment registers with a flat 4 GB address space and EFLAGS.IF = 0.
+ * Depending on the previous sleep state, we may need to initialize more
+ * of the system (i.e., S3 suspend-to-RAM vs. S4 suspend-to-disk).
+ */
.align 4
.code16
wakeup_16:
nop
cli
+ cld
/*
- * Set up segment registers for real mode and a small stack for
- * any calls we make.
+ * Set up segment registers for real mode, a small stack for
+ * any calls we make, and clear any flags.
*/
movw %cs,%ax
movw %ax,%ds
movw %ax,%ss
movw $PAGE_SIZE,%sp
+ pushl $0
+ popfl
/* To debug resume hangs, beep the speaker if the user requested. */
cmpl $1,resume_beep
@@ -75,22 +85,22 @@ nobeep:
movw %ax,%ss
nobiosreset:
- /* Load GDT for real mode */
- lgdt physical_gdt
+ /* Load GDT for real mode. Use 32 bit prefix for addresses >16 MB. */
+ lgdtl physical_gdt
/* Restore CR2, CR3 and CR4 */
- mov previous_cr2,%eax
- mov %eax,%cr2
- mov previous_cr3,%eax
- mov %eax,%cr3
- mov previous_cr4,%eax
- mov %eax,%cr4
-
- /* Transfer some values to protected mode */
+ movl previous_cr2,%eax
+ movl %eax,%cr2
+ movl previous_cr3,%eax
+ movl %eax,%cr3
+ movl previous_cr4,%eax
+ movl %eax,%cr4
+
+ /* Transfer some values to protected mode with an inline stack */
#define NVALUES 9
#define TRANSFER_STACK32(val, idx) \
- mov val,%eax; \
- mov %eax,wakeup_32stack+(idx+1)+(idx*4);
+ movl val,%eax; \
+ movl %eax,wakeup_32stack+(idx+1)+(idx*4)
TRANSFER_STACK32(previous_ss, (NVALUES - 9))
TRANSFER_STACK32(previous_fs, (NVALUES - 8))
@@ -106,21 +116,20 @@ nobiosreset:
mov physical_esp,%esi /* to be used in 32bit code */
/* Enable protected mode */
- mov %cr0,%eax
+ movl %cr0,%eax
orl $(CR0_PE),%eax
- mov %eax,%cr0
+ movl %eax,%cr0
wakeup_sw32:
/* Switch to protected mode by intersegmental jump */
ljmpl $KCSEL,$0x12345678 /* Code location, to be replaced */
- .code32
-wakeup_32:
/*
- * Switched to protected mode w/o paging
- * %esi: KERNEL stack pointer (physical address)
+ * Now switched to protected mode without paging enabled.
+ * %esi: KERNEL stack pointer (physical address)
*/
-
+ .code32
+wakeup_32:
nop
/* Set up segment registers for protected mode */
@@ -134,13 +143,13 @@ wakeup_32:
movl %esi,%esp /* physical address stack pointer */
wakeup_32stack:
- /* Operands are overwritten in 16bit code */
+ /* Operands are overwritten in 16 bit code by TRANSFER_STACK32 macro */
pushl $0xabcdef09 /* ss + dummy */
pushl $0xabcdef08 /* fs + gs */
pushl $0xabcdef07 /* ds + es */
pushl $0xabcdef06 /* gdt:base (physical address) */
- pushl $0xabcdef05 /* recover address */
- pushl $0xabcdef04 /* idt:base */
+ pushl $0xabcdef05 /* recover address */
+ pushl $0xabcdef04 /* idt:base */
pushl $0xabcdef03 /* ldt + idt:limit */
pushl $0xabcdef02 /* gdt:base */
pushl $0xabcdef01 /* TR + gdt:limit */
@@ -169,15 +178,10 @@ wakeup_32stack:
andb $TSS_TYPEFIX_MASK,5(%eax)
/* Prepare to return to sleep/wakeup code point */
- lgdt PREVIOUS_GDT
- lidt PREVIOUS_IDT
-
- xorl %eax,%eax
- movl %eax,%ebx
- movl %eax,%ecx
- movl %eax,%edx
- movl %eax,%esi
- movl %eax,%edi
+ lgdtl PREVIOUS_GDT
+ lidtl PREVIOUS_IDT
+
+ /* Pack values from the GDT to be loaded into segment registers. */
movl PREVIOUS_DS,%ebx
movl PREVIOUS_FS,%ecx
movl PREVIOUS_SS,%edx
@@ -194,15 +198,17 @@ wakeup_32stack:
jmp 1f
1: jmp 1f
1:
+
/*
- * Now that we are in kernel virtual memory addressing
- * %ebx: ds + es
- * %ecx: fs + gs
- * %edx: ss + dummy
- * %esi: LDTR + TR
- * %edi: recover address
+ * Now we are in kernel virtual memory addressing with the following
+ * original register values:
+ * %ebx: ds + es
+ * %ecx: fs + gs
+ * %edx: ss + dummy
+ * %esi: LDTR + TR
+ * %edi: recover address
+ * We'll load these back into the segment registers now.
*/
-
nop
movl %esi,%eax /* LDTR + TR */
@@ -235,7 +241,10 @@ previous_cr4: .long 0
resume_beep: .long 0
reset_video: .long 0
-/* transfer from real mode to protected mode */
+/*
+ * Transfer from real mode to protected mode. The order of these variables
+ * is very important, DO NOT INSERT OR CHANGE unless you know why.
+ */
previous_cr0: .long 0
previous_tr: .word 0
previous_gdt: .word 0
OpenPOWER on IntegriCloud