aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/idle/mrst_s0i3_asm.S
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2010-12-03 10:30:34 -0800
committerH. Peter Anvin <hpa@linux.intel.com>2010-12-14 10:48:40 -0800
commit8062e70d346f6be5aae1d0064890a934bd4e9209 (patch)
tree3a2b1132d370e11e8d15f4361498a39759fface8 /drivers/idle/mrst_s0i3_asm.S
parent58d95233ad8aa2fde72f8b9ebbf8ebbd91635358 (diff)
downloadmrst-s0i3-test-8062e70d346f6be5aae1d0064890a934bd4e9209.tar.gz
mrst-s0i3-test-8062e70d346f6be5aae1d0064890a934bd4e9209.tar.xz
mrst-s0i3-test-8062e70d346f6be5aae1d0064890a934bd4e9209.zip
Initial S0i3 code test
Diffstat (limited to 'drivers/idle/mrst_s0i3_asm.S')
-rw-r--r--drivers/idle/mrst_s0i3_asm.S162
1 files changed, 162 insertions, 0 deletions
diff --git a/drivers/idle/mrst_s0i3_asm.S b/drivers/idle/mrst_s0i3_asm.S
new file mode 100644
index 00000000000..6ad08b4fac2
--- /dev/null
+++ b/drivers/idle/mrst_s0i3_asm.S
@@ -0,0 +1,162 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2 or (at your
+ * option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+#include <asm/msr-index.h>
+#include <asm/page.h>
+#include <asm/segment.h>
+
+#include "mrst_s0i3.h"
+
+/* Physical address */
+#define pa(X) ((X) - __PAGE_OFFSET)
+
+ .code32 /* MRST boots up in flat 32-bit mode */
+ .text
+ENTRY(mrst_s0i3_entry)
+ pushl %edi
+ pushl %esi
+ pushl %ebp
+ pushl %ebx
+
+ movl %esp, %esi
+
+ subl $8, %esp
+ sidtl 2(%esp)
+
+ pushl %gs
+ pushl %fs
+
+ movl %cr3, %eax
+ pushl %eax
+
+ subl $8, %esp
+ sgdtl 2(%esp)
+
+ movl %cr0, %eax
+ pushl %eax
+
+ movl %cr4, %eax
+ pushl %eax
+
+ movl $(MSR_EFER), %ecx
+ rdmsr
+ pushl %edx
+ pushl %eax
+
+ movl (32-12)(%esp), %eax /* GDT base */
+ subl $(__PAGE_OFFSET), %eax /* Convert to a physical address */
+ pushl %eax
+ pushl (28-8)(%esp) /* GDT length, pad */
+
+ pushfl
+
+ leal (-__PAGE_OFFSET)(%esp), %eax
+ movl %eax, mrst_s0i3_resume_stack
+
+ wbinvd
+
+ movl %esp, %eax /* As good as anything... */
+ xorl %edx, %edx
+ xorl %ecx, %ecx
+ monitor
+
+ movl $MRST_C6_HINTS_EAX, %eax
+ movl $MRST_C6_HINTS_ECX, %ecx
+ sti
+ mwait
+
+ /* If MWAIT wakes us up, assume something happened... */
+ cli
+ movl %esi, %esp
+
+ xorl %eax, %eax /* Not really S0i3 */
+ popl %ebx
+ popl %ebp
+ popl %esi
+ popl %edi
+ ret
+END(mrst_s0i3_entry)
+
+/*
+ * After S0i3 the MRST firmare will put us back in 32-bit flat mode
+ */
+ENTRY(mrst_s0i3_resume)
+ cli
+
+ movl pa(mrst_s0i3_resume_stack), %esp
+ popfl /* 0 - %eflags */
+ lgdtl 2(%esp) /* 4 - physical GDT pointer */
+
+ addl $8, %esp
+ movl $(__KERNEL_DS), %eax
+ movl %eax, %ss
+ movl %eax, %ds
+ movl %eax, %es
+
+ popl %eax
+ popl %edx
+ movl $(MSR_IA32_MISC_ENABLE), %ecx /* 12 - MISC_ENABLE MSR */
+ wrmsr
+
+ popl %eax /* 12 - EFER */
+ popl %edx
+ movl $(MSR_EFER), %ecx
+ wrmsr
+
+ popl %eax /* 20 - %cr4 */
+ movl %eax, %cr4
+
+ movl $pa(initial_page_table), %eax
+ movl %eax, %cr3
+
+ popl %eax /* 24 - %cr0 */
+ movl %eax, %cr0 /* Enables paging! */
+ ljmpl $(__KERNEL_CS), $1f
+1:
+
+ addl $__PAGE_OFFSET, %esp
+ lgdtl 2(%esp) /* 32 - linear GDT pointer */
+ popl %ebx /* 32 - GDT length + junk */
+ popl %ebx /* 32 - linear address of GDT */
+
+ popl %eax /* 36 - %cr3 */
+ movl %eax, %cr3
+
+ movl $(GDT_ENTRY_TSS*8), %eax
+ andb $~0x02, (GDT_ENTRY_TSS*8+5) /* Clear the TSS busy bit */
+ ltr %ax /* Set the TSS */
+
+ popl %fs /* 40 - %fs */
+ popl %gs /* 44 - %gs */
+
+ /* x86-64 would need to restore MSR_GS_BASE too */
+
+ lidtl 2(%esp) /* 48 - IDT pointer */
+ addl $8, %esp
+
+ popl %eax /* 56 - %ldtr */
+ lldt %ax
+
+ movl $1, %eax /* Resume from actual S0i3 */
+ popl %ebx
+ popl %ebp
+ popl %esi
+ popl %edi
+
+ ret
+END(mrst_s0i3_resume)
+
+ .bss
+ .balign 4
+ENTRY(mrst_s0i3_resume_stack)
+ .space 4
+END(mrst_s0i3_resume_stack)