* factor out common s2ram wakeup code
@ 2008-01-22 19:37 Pavel Machek
2008-01-22 20:27 ` H. Peter Anvin
2008-01-24 0:20 ` Rafael J. Wysocki
0 siblings, 2 replies; 9+ messages in thread
From: Pavel Machek @ 2008-01-22 19:37 UTC (permalink / raw)
To: Rafael J. Wysocki, kernel list, mingo, tglx, hpa
It seems to compile 32/64bit, and work 32bit... Now, video code should
be probably shared with kernel/boot; but that was rewritten to C and
I'm not sure if I know enough about linkers... basically the C code
should replace mode_set() and friends. Peter, can you help?
Pavel
---
Factor out common real-mode part of wakeup_{32,64}.S.
Signed-off-by: Pavel Machek <pavel@suse.cz>
---
commit 2fac1886274433c64e76611e6b1ba2318c5914a4
tree 2d6bdc7c2eda9845b57e1d7128b187df1b1fd2c9
parent 7a9546efcc4d90040a52c003eb9a303200c41f86
author Pavel <pavel@amd.ucw.cz> Tue, 22 Jan 2008 20:34:03 +0100
committer Pavel <pavel@amd.ucw.cz> Tue, 22 Jan 2008 20:34:03 +0100
arch/x86/kernel/acpi/wakeup.S | 111 ++++++++++++++++++++++++++++++++++
arch/x86/kernel/acpi/wakeup_32.S | 118 +-----------------------------------
arch/x86/kernel/acpi/wakeup_64.S | 125 +-------------------------------------
3 files changed, 116 insertions(+), 238 deletions(-)
diff --git a/arch/x86/kernel/acpi/wakeup.S b/arch/x86/kernel/acpi/wakeup.S
new file mode 100644
index 0000000..38205c8
--- /dev/null
+++ b/arch/x86/kernel/acpi/wakeup.S
@@ -0,0 +1,111 @@
+# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
+
+#define BEEP \
+ inb $97, %al; \
+ outb %al, $0x80; \
+ movb $3, %al; \
+ outb %al, $97; \
+ outb %al, $0x80; \
+ movb $-74, %al; \
+ outb %al, $67; \
+ outb %al, $0x80; \
+ movb $-119, %al; \
+ outb %al, $66; \
+ outb %al, $0x80; \
+ movb $15, %al; \
+ outb %al, $66;
+
+ALIGN
+ .align 4096
+ENTRY(wakeup_start)
+wakeup_code:
+ wakeup_code_start = .
+ .code16
+
+ cli
+ cld
+
+ # setup data segment
+ movw %cs, %ax
+ movw %ax, %ds # Make ds:0 point to wakeup_start
+ movw %ax, %ss
+
+ testl $4, realmode_flags - wakeup_code
+ jz 1f
+ BEEP
+1:
+ mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board
+
+ pushl $0 # Kill any dangerous flags
+ popfl
+
+
+ movl real_magic - wakeup_code, %eax
+ cmpl $0x12345678, %eax
+ jne bogus_real_magic
+
+ testl $1, realmode_flags - wakeup_code
+ jz 1f
+ lcall $0xc000,$3
+ movw %cs, %ax
+ movw %ax, %ds # Bios might have played with that
+ movw %ax, %ss
+1:
+
+ testl $2, realmode_flags - wakeup_code
+ jz mode_done
+ mov video_mode - wakeup_code, %ax
+ call mode_set
+ jmp mode_done
+
+/* This code uses an extended set of video mode numbers. These include:
+ * Aliases for standard modes
+ * NORMAL_VGA (-1)
+ * EXTENDED_VGA (-2)
+ * ASK_VGA (-3)
+ * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
+ * of compatibility when extending the table. These are between 0x00 and 0xff.
+ */
+#define VIDEO_FIRST_MENU 0x0000
+
+/* Standard BIOS video modes (BIOS number + 0x0100) */
+#define VIDEO_FIRST_BIOS 0x0100
+
+/* VESA BIOS video modes (VESA number + 0x0200) */
+#define VIDEO_FIRST_VESA 0x0200
+
+/* Video7 special modes (BIOS number + 0x0900) */
+#define VIDEO_FIRST_V7 0x0900
+
+# Setting of user mode (AX=mode ID) => CF=success
+
+# For now, we only handle VESA modes (0x0200..0x03ff). To handle other
+# modes, we should probably compile in the video code from the boot
+# directory.
+.code16
+mode_set:
+ movw %ax, %bx
+ subb $VIDEO_FIRST_VESA>>8, %bh
+ cmpb $2, %bh
+ jb check_vesa
+
+setbad:
+ clc
+ ret
+
+check_vesa:
+ orw $0x4000, %bx # Use linear frame buffer
+ movw $0x4f02, %ax # VESA BIOS mode set call
+ int $0x10
+ cmpw $0x004f, %ax # AL=4f if implemented
+ jnz setbad # AH=0 if OK
+
+ stc
+ ret
+
+bogus_real_magic:
+ jmp bogus_real_magic
+
+real_magic: .quad 0
+video_mode: .quad 0
+realmode_flags: .quad 0
diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S
index 1e931aa..9b26909 100644
--- a/arch/x86/kernel/acpi/wakeup_32.S
+++ b/arch/x86/kernel/acpi/wakeup_32.S
@@ -3,73 +3,11 @@ #include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page.h>
-#
-# wakeup_code runs in real mode, and at unknown address (determined at run-time).
-# Therefore it must only use relative jumps/calls.
-#
-# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
-#
-# If physical address of wakeup_code is 0x12345, BIOS should call us with
-# cs = 0x1234, eip = 0x05
-#
-
-#define BEEP \
- inb $97, %al; \
- outb %al, $0x80; \
- movb $3, %al; \
- outb %al, $97; \
- outb %al, $0x80; \
- movb $-74, %al; \
- outb %al, $67; \
- outb %al, $0x80; \
- movb $-119, %al; \
- outb %al, $66; \
- outb %al, $0x80; \
- movb $15, %al; \
- outb %al, $66;
-
-ALIGN
- .align 4096
-ENTRY(wakeup_start)
-wakeup_code:
- wakeup_code_start = .
- .code16
-
- cli
- cld
-
- # setup data segment
- movw %cs, %ax
- movw %ax, %ds # Make ds:0 point to wakeup_start
- movw %ax, %ss
-
- testl $4, realmode_flags - wakeup_code
- jz 1f
- BEEP
-1:
- mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board
+# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
- pushl $0 # Kill any dangerous flags
- popfl
-
- movl real_magic - wakeup_code, %eax
- cmpl $0x12345678, %eax
- jne bogus_real_magic
-
- testl $1, realmode_flags - wakeup_code
- jz 1f
- lcall $0xc000,$3
- movw %cs, %ax
- movw %ax, %ds # Bios might have played with that
- movw %ax, %ss
-1:
-
- testl $2, realmode_flags - wakeup_code
- jz 1f
- mov video_mode - wakeup_code, %ax
- call mode_set
-1:
+#include "wakeup.S"
+mode_done:
# set up page table
movl $swsusp_pg_dir-__PAGE_OFFSET, %eax
movl %eax, %cr3
@@ -109,60 +47,10 @@ real_save_gdt: .word 0
real_save_cr0: .long 0
real_save_cr3: .long 0
real_save_cr4: .long 0
-real_magic: .long 0
-video_mode: .long 0
-realmode_flags: .long 0
real_efer_save_restore: .long 0
real_save_efer_edx: .long 0
real_save_efer_eax: .long 0
-bogus_real_magic:
- jmp bogus_real_magic
-
-/* This code uses an extended set of video mode numbers. These include:
- * Aliases for standard modes
- * NORMAL_VGA (-1)
- * EXTENDED_VGA (-2)
- * ASK_VGA (-3)
- * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
- * of compatibility when extending the table. These are between 0x00 and 0xff.
- */
-#define VIDEO_FIRST_MENU 0x0000
-
-/* Standard BIOS video modes (BIOS number + 0x0100) */
-#define VIDEO_FIRST_BIOS 0x0100
-
-/* VESA BIOS video modes (VESA number + 0x0200) */
-#define VIDEO_FIRST_VESA 0x0200
-
-/* Video7 special modes (BIOS number + 0x0900) */
-#define VIDEO_FIRST_V7 0x0900
-
-# Setting of user mode (AX=mode ID) => CF=success
-
-# For now, we only handle VESA modes (0x0200..0x03ff). To handle other
-# modes, we should probably compile in the video code from the boot
-# directory.
-mode_set:
- movw %ax, %bx
- subb $VIDEO_FIRST_VESA>>8, %bh
- cmpb $2, %bh
- jb check_vesa
-
-setbad:
- clc
- ret
-
-check_vesa:
- orw $0x4000, %bx # Use linear frame buffer
- movw $0x4f02, %ax # VESA BIOS mode set call
- int $0x10
- cmpw $0x004f, %ax # AL=4f if implemented
- jnz setbad # AH=0 if OK
-
- stc
- ret
-
.code32
ALIGN
diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S
index 5ed3bc5..b02d97f 100644
--- a/arch/x86/kernel/acpi/wakeup_64.S
+++ b/arch/x86/kernel/acpi/wakeup_64.S
@@ -7,78 +7,10 @@ #include <asm/msr.h>
#include <asm/asm-offsets.h>
# Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
-#
-# wakeup_code runs in real mode, and at unknown address (determined at run-time).
-# Therefore it must only use relative jumps/calls.
-#
-# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
-#
-# If physical address of wakeup_code is 0x12345, BIOS should call us with
-# cs = 0x1234, eip = 0x05
-#
-
-#define BEEP \
- inb $97, %al; \
- outb %al, $0x80; \
- movb $3, %al; \
- outb %al, $97; \
- outb %al, $0x80; \
- movb $-74, %al; \
- outb %al, $67; \
- outb %al, $0x80; \
- movb $-119, %al; \
- outb %al, $66; \
- outb %al, $0x80; \
- movb $15, %al; \
- outb %al, $66;
-
-
-ALIGN
- .align 16
-ENTRY(wakeup_start)
-wakeup_code:
- wakeup_code_start = .
- .code16
-
-# Running in *copy* of this code, somewhere in low 1MB.
-
- cli
- cld
- # setup data segment
- movw %cs, %ax
- movw %ax, %ds # Make ds:0 point to wakeup_start
- movw %ax, %ss
-
- # Data segment must be set up before we can see whether to beep.
- testl $4, realmode_flags - wakeup_code
- jz 1f
- BEEP
-1:
-
- # Private stack is needed for ASUS board
- mov $(wakeup_stack - wakeup_code), %sp
-
- pushl $0 # Kill any dangerous flags
- popfl
- movl real_magic - wakeup_code, %eax
- cmpl $0x12345678, %eax
- jne bogus_real_magic
-
- testl $1, realmode_flags - wakeup_code
- jz 1f
- lcall $0xc000,$3
- movw %cs, %ax
- movw %ax, %ds # Bios might have played with that
- movw %ax, %ss
-1:
-
- testl $2, realmode_flags - wakeup_code
- jz 1f
- mov video_mode - wakeup_code, %ax
- call mode_set
-1:
+#include "wakeup.S"
+mode_done:
mov %ds, %ax # Find 32bit wakeup_code addr
movzx %ax, %esi # (Convert %ds:gdt to a liner ptr)
shll $4, %esi
@@ -227,64 +159,11 @@ gdt_48a:
.word 0x800 # gdt limit=2048,
# 256 GDT entries
.long gdta - wakeup_code # gdt base (relocated in later)
-
-real_magic: .quad 0
-video_mode: .quad 0
-realmode_flags: .quad 0
-
-.code16
-bogus_real_magic:
- jmp bogus_real_magic
.code64
bogus_64_magic:
jmp bogus_64_magic
-/* This code uses an extended set of video mode numbers. These include:
- * Aliases for standard modes
- * NORMAL_VGA (-1)
- * EXTENDED_VGA (-2)
- * ASK_VGA (-3)
- * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
- * of compatibility when extending the table. These are between 0x00 and 0xff.
- */
-#define VIDEO_FIRST_MENU 0x0000
-
-/* Standard BIOS video modes (BIOS number + 0x0100) */
-#define VIDEO_FIRST_BIOS 0x0100
-
-/* VESA BIOS video modes (VESA number + 0x0200) */
-#define VIDEO_FIRST_VESA 0x0200
-
-/* Video7 special modes (BIOS number + 0x0900) */
-#define VIDEO_FIRST_V7 0x0900
-
-# Setting of user mode (AX=mode ID) => CF=success
-
-# For now, we only handle VESA modes (0x0200..0x03ff). To handle other
-# modes, we should probably compile in the video code from the boot
-# directory.
-.code16
-mode_set:
- movw %ax, %bx
- subb $VIDEO_FIRST_VESA>>8, %bh
- cmpb $2, %bh
- jb check_vesa
-
-setbad:
- clc
- ret
-
-check_vesa:
- orw $0x4000, %bx # Use linear frame buffer
- movw $0x4f02, %ax # VESA BIOS mode set call
- int $0x10
- cmpw $0x004f, %ax # AL=4f if implemented
- jnz setbad # AH=0 if OK
-
- stc
- ret
-
wakeup_stack_begin: # Stack grows down
.org 0xff0
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: factor out common s2ram wakeup code 2008-01-22 19:37 factor out common s2ram wakeup code Pavel Machek @ 2008-01-22 20:27 ` H. Peter Anvin [not found] ` <20080122205625.GC4317@elf.ucw.cz> 2008-01-24 0:20 ` Rafael J. Wysocki 1 sibling, 1 reply; 9+ messages in thread From: H. Peter Anvin @ 2008-01-22 20:27 UTC (permalink / raw) To: Pavel Machek; +Cc: Rafael J. Wysocki, kernel list, mingo, tglx Pavel Machek wrote: > It seems to compile 32/64bit, and work 32bit... Now, video code should > be probably shared with kernel/boot; but that was rewritten to C and > I'm not sure if I know enough about linkers... basically the C code > should replace mode_set() and friends. Peter, can you help? Yes, absolutely. I think we should probably segregate out into a subdirectory the part of the code that should be run in 16-bit mode, and then it's just a matter of pretty much replicating the mechanisms used in arch/x86/boot. How can I best be of help? -hpa ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <20080122205625.GC4317@elf.ucw.cz>]
[parent not found: <47965B13.9080705@zytor.com>]
* Re: factor out common s2ram wakeup code [not found] ` <47965B13.9080705@zytor.com> @ 2008-01-22 21:24 ` Pavel Machek 2008-01-22 21:51 ` H. Peter Anvin 0 siblings, 1 reply; 9+ messages in thread From: Pavel Machek @ 2008-01-22 21:24 UTC (permalink / raw) To: H. Peter Anvin; +Cc: kernel list, Rafael J. Wysocki Hi! (Lists added back to CC, I dropped them by mistake). >>>> It seems to compile 32/64bit, and work 32bit... Now, video code should >>>> be probably shared with kernel/boot; but that was rewritten to C and >>>> I'm not sure if I know enough about linkers... basically the C code >>>> should replace mode_set() and friends. Peter, can you help? >>> Yes, absolutely. I think we should probably segregate out into a >>> subdirectory the part of the code that should be run in 16-bit mode, and >>> then it's just a matter of pretty much replicating the mechanisms used in >>> arch/x86/boot. >> >> I'd basically need second copy of bootup code, placed into page with >> wakeup_code. I guess I could let gcc compile .c into .s , and then >> include that... but perhaps there is better way? >> >>> How can I best be of help? >> >> Teach me how to include .c into wakeup.S. I should be able to figure >> the rest... > > Yes, there is a better way. > > The biggest question is if your 16-bit code needs to touch symbols in the > 32/64-bit code, or vice versa. That complicates things a little bit, > obviously. The code is in arch/x86/kernel/acpi/wakeup_32.S . acpi_copy_wakeup_routine needs to know offsets within 16-bit code. I'd like to somehow call code from arch/x86/boot/video*.c ... current version just took (old) .S code, and cut&paste-s it. > If not, the easiest way is to link the 16-bit code into a separate binary > (including both assembly and C code) which can then be included in the > kernel proper as a binary blob. If it *does* need to reference outside > symbols, then it needs to be part of the overall link, which means mucking > with the top-level link script. > That's obviously more complex. > > Either way, the Makefile bit of this will be a lot easier if we move the > 16-bit code into a separate directory. I only need arch/x86/boot/video*.c ... > Let me know which way you think makes more sense, and I can send you a > framework patch. I need to access data in that 16-bit code... Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: factor out common s2ram wakeup code 2008-01-22 21:24 ` Pavel Machek @ 2008-01-22 21:51 ` H. Peter Anvin 2008-01-22 22:03 ` Pavel Machek 0 siblings, 1 reply; 9+ messages in thread From: H. Peter Anvin @ 2008-01-22 21:51 UTC (permalink / raw) To: Pavel Machek; +Cc: kernel list, Rafael J. Wysocki Pavel Machek wrote: >> >> The biggest question is if your 16-bit code needs to touch symbols in the >> 32/64-bit code, or vice versa. That complicates things a little bit, >> obviously. > > The code is in arch/x86/kernel/acpi/wakeup_32.S > . acpi_copy_wakeup_routine needs to know offsets within 16-bit > code. I'd like to somehow call code from arch/x86/boot/video*.c > ... current version just took (old) .S code, and cut&paste-s it. > Right, I know. >> If not, the easiest way is to link the 16-bit code into a separate binary >> (including both assembly and C code) which can then be included in the >> kernel proper as a binary blob. If it *does* need to reference outside >> symbols, then it needs to be part of the overall link, which means mucking >> with the top-level link script. >> That's obviously more complex. >> >> Either way, the Makefile bit of this will be a lot easier if we move the >> 16-bit code into a separate directory. > > I only need arch/x86/boot/video*.c ... > >> Let me know which way you think makes more sense, and I can send you a >> framework patch. > > I need to access data in that 16-bit code... Would a shared structure be OK for that? That's easier than dealing with symbols. -hpa ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: factor out common s2ram wakeup code 2008-01-22 21:51 ` H. Peter Anvin @ 2008-01-22 22:03 ` Pavel Machek 2008-01-22 22:09 ` H. Peter Anvin [not found] ` <47969BB2.2020409@zytor.com> 0 siblings, 2 replies; 9+ messages in thread From: Pavel Machek @ 2008-01-22 22:03 UTC (permalink / raw) To: H. Peter Anvin; +Cc: kernel list, Rafael J. Wysocki On Tue 2008-01-22 13:51:02, H. Peter Anvin wrote: > Pavel Machek wrote: >>> >>> The biggest question is if your 16-bit code needs to touch symbols in the >>> 32/64-bit code, or vice versa. That complicates things a little bit, >>> obviously. >> >> The code is in arch/x86/kernel/acpi/wakeup_32.S >> . acpi_copy_wakeup_routine needs to know offsets within 16-bit code. I'd >> like to somehow call code from arch/x86/boot/video*.c >> ... current version just took (old) .S code, and cut&paste-s it. >> > > Right, I know. > >>> If not, the easiest way is to link the 16-bit code into a separate binary >>> (including both assembly and C code) which can then be included in the >>> kernel proper as a binary blob. If it *does* need to reference outside >>> symbols, then it needs to be part of the overall link, which means >>> mucking with the top-level link script. >>> That's obviously more complex. >>> >>> Either way, the Makefile bit of this will be a lot easier if we move the >>> 16-bit code into a separate directory. >> >> I only need arch/x86/boot/video*.c ... >> >>> Let me know which way you think makes more sense, and I can send you a >>> framework patch. >> >> I need to access data in that 16-bit code... > > Would a shared structure be OK for that? That's easier than dealing with > symbols. Shared structure would be okay, plus I need pointer to beggining and end of code so that I can copy it to lowmem. Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: factor out common s2ram wakeup code 2008-01-22 22:03 ` Pavel Machek @ 2008-01-22 22:09 ` H. Peter Anvin [not found] ` <47969BB2.2020409@zytor.com> 1 sibling, 0 replies; 9+ messages in thread From: H. Peter Anvin @ 2008-01-22 22:09 UTC (permalink / raw) To: Pavel Machek; +Cc: kernel list, Rafael J. Wysocki Pavel Machek wrote: > > Shared structure would be okay, plus I need pointer to beggining and > end of code so that I can copy it to lowmem. > Pavel OK, that's easy. -hpa ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <47969BB2.2020409@zytor.com>]
* Re: factor out common s2ram wakeup code [not found] ` <47969BB2.2020409@zytor.com> @ 2008-01-25 23:12 ` Pavel Machek 2008-01-25 23:36 ` H. Peter Anvin 0 siblings, 1 reply; 9+ messages in thread From: Pavel Machek @ 2008-01-25 23:12 UTC (permalink / raw) To: H. Peter Anvin, kernel list, Linux-pm mailing list, Rafael J. Wysocki Hi! > Here is a patch which at least compiles (but doesn't link, since the > interface to the higher-level ACPI code needs to be adjusted). Thanks a lot! Here is patch that seems to work a bit... video settings are hardcoded at mode 6 for now. Pavel diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 7a3116c..6e97bfa 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -30,7 +30,8 @@ subdir- := compressed setup-y += a20.o apm.o cmdline.o copy.o cpu.o cpucheck.o edd.o setup-y += header.o main.o mca.o memory.o pm.o pmjump.o -setup-y += printf.o string.o tty.o video.o version.o voyager.o +setup-y += printf.o string.o tty.o video.o video-mode.o +setup-y += version.o voyager.o # The link order of the video-*.o modules can matter. In particular, # video-vga.o *must* be listed first, followed by video-vesa.o. diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index d2b5adf..5f45286 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -285,6 +285,11 @@ int getchar_timeout(void); /* video.c */ void set_video(void); +/* video-mode.c */ +int set_mode(u16 mode); +int mode_defined(u16 mode); +void probe_cards(int unsafe); + /* video-vesa.c */ void vesa_store_edid(void); diff --git a/arch/x86/boot/video-bios.c b/arch/x86/boot/video-bios.c index ed0672a..a36edbd 100644 --- a/arch/x86/boot/video-bios.c +++ b/arch/x86/boot/video-bios.c @@ -50,6 +50,7 @@ static int set_bios_mode(u8 mode) if (new_mode == mode) return 0; /* Mode change OK */ +#ifndef _WAKEUP if (new_mode != boot_params.screen_info.orig_video_mode) { /* Mode setting failed, but we didn't end up where we started. That's bad. Try to revert to the original @@ -59,13 +60,18 @@ static int set_bios_mode(u8 mode) : "+a" (ax) : : "ebx", "ecx", "edx", "esi", "edi"); } +#endif return -1; } static int bios_probe(void) { u8 mode; +#ifdef _WAKEUP + u8 saved_mode = 0x03; +#else u8 saved_mode = boot_params.screen_info.orig_video_mode; +#endif u16 crtc; struct mode_info *mi; int nmodes = 0; diff --git a/arch/x86/boot/video-mode.c b/arch/x86/boot/video-mode.c new file mode 100644 index 0000000..18bacb3 --- /dev/null +++ b/arch/x86/boot/video-mode.c @@ -0,0 +1,173 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007-2008 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * arch/i386/boot/video-mode.c + * + * Set the video mode. This is separated out into a different + * file in order to be shared with the ACPI wakeup code. + */ + +#include "boot.h" +#include "video.h" +#include "vesa.h" + +/* + * Common variables + */ +int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */ +u16 video_segment; +int force_x, force_y; /* Don't query the BIOS for cols/rows */ + +int do_restore = 0; /* Screen contents changed during mode flip */ +int graphic_mode; /* Graphic mode with linear frame buffer */ + +/* Probe the video drivers and have them generate their mode lists. */ +void probe_cards(int unsafe) +{ + struct card_info *card; + static u8 probed[2]; + + if (probed[unsafe]) + return; + + probed[unsafe] = 1; + + for (card = video_cards; card < video_cards_end; card++) { + if (card->unsafe == unsafe) { + if (card->probe) + card->nmodes = card->probe(); + else + card->nmodes = 0; + } + } +} + +/* Test if a mode is defined */ +int mode_defined(u16 mode) +{ + struct card_info *card; + struct mode_info *mi; + int i; + + for (card = video_cards; card < video_cards_end; card++) { + mi = card->modes; + for (i = 0; i < card->nmodes; i++, mi++) { + if (mi->mode == mode) + return 1; + } + } + + return 0; +} + +/* Set mode (without recalc) */ +static int raw_set_mode(u16 mode, u16 *real_mode) +{ + int nmode, i; + struct card_info *card; + struct mode_info *mi; + + /* Drop the recalc bit if set */ + mode &= ~VIDEO_RECALC; + + /* Scan for mode based on fixed ID, position, or resolution */ + nmode = 0; + for (card = video_cards; card < video_cards_end; card++) { + mi = card->modes; + for (i = 0; i < card->nmodes; i++, mi++) { + int visible = mi->x || mi->y; + + if ((mode == nmode && visible) || + mode == mi->mode || + mode == (mi->y << 8)+mi->x) { + *real_mode = mi->mode; + return card->set_mode(mi); + } + + if (visible) + nmode++; + } + } + + /* Nothing found? Is it an "exceptional" (unprobed) mode? */ + for (card = video_cards; card < video_cards_end; card++) { + if (mode >= card->xmode_first && + mode < card->xmode_first+card->xmode_n) { + struct mode_info mix; + *real_mode = mix.mode = mode; + mix.x = mix.y = 0; + return card->set_mode(&mix); + } + } + + /* Otherwise, failure... */ + return -1; +} + +/* + * Recalculate the vertical video cutoff (hack!) + */ +static void vga_recalc_vertical(void) +{ + unsigned int font_size, rows; + u16 crtc; + u8 pt, ov; + + set_fs(0); + font_size = rdfs8(0x485); /* BIOS: font size (pixels) */ + rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */ + + rows *= font_size; /* Visible scan lines */ + rows--; /* ... minus one */ + + crtc = vga_crtc(); + + pt = in_idx(crtc, 0x11); + pt &= ~0x80; /* Unlock CR0-7 */ + out_idx(pt, crtc, 0x11); + + out_idx((u8)rows, crtc, 0x12); /* Lower height register */ + + ov = in_idx(crtc, 0x07); /* Overflow register */ + ov &= 0xbd; + ov |= (rows >> (8-1)) & 0x02; + ov |= (rows >> (9-6)) & 0x40; + out_idx(ov, crtc, 0x07); +} + +/* Set mode (with recalc if specified) */ +int set_mode(u16 mode) +{ + int rv; + u16 real_mode; + + /* Very special mode numbers... */ + if (mode == VIDEO_CURRENT_MODE) + return 0; /* Nothing to do... */ + else if (mode == NORMAL_VGA) + mode = VIDEO_80x25; + else if (mode == EXTENDED_VGA) + mode = VIDEO_8POINT; + + rv = raw_set_mode(mode, &real_mode); + if (rv) + return rv; + + if (mode & VIDEO_RECALC) + vga_recalc_vertical(); + + /* Save the canonical mode number for the kernel, not + an alias, size specification or menu position */ +#ifndef _WAKEUP + boot_params.hdr.vid_mode = real_mode; +#endif + return 0; +} diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c index 4716b9a..ec43f28 100644 --- a/arch/x86/boot/video-vesa.c +++ b/arch/x86/boot/video-vesa.c @@ -152,7 +152,9 @@ static int vesa_set_mode(struct mode_inf do_restore = 1; } else { /* Graphics mode */ +#ifndef _WAKEUP vesa_store_mode_params_graphics(); +#endif } return 0; @@ -179,6 +181,7 @@ static void vesa_dac_set_8bits(void) } /* Set the color sizes to the DAC size, and offsets to 0 */ +#ifndef _WAKEUP boot_params.screen_info.red_size = dac_size; boot_params.screen_info.green_size = dac_size; boot_params.screen_info.blue_size = dac_size; @@ -188,8 +191,11 @@ static void vesa_dac_set_8bits(void) boot_params.screen_info.green_pos = 0; boot_params.screen_info.blue_pos = 0; boot_params.screen_info.rsvd_pos = 0; +#endif } +#ifndef _WAKEUP + /* Save the VESA protected mode info */ static void vesa_store_pm_info(void) { @@ -282,6 +288,8 @@ #ifdef CONFIG_FIRMWARE_EDID #endif /* CONFIG_FIRMWARE_EDID */ } +#endif /* not _WAKEUP */ + __videocard video_vesa = { .card_name = "VESA", diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c index aef02f9..6be3658 100644 --- a/arch/x86/boot/video-vga.c +++ b/arch/x86/boot/video-vga.c @@ -210,6 +210,8 @@ static int vga_set_mode(struct mode_info */ static int vga_probe(void) { + u16 ega_bx; + static const char *card_name[] = { "CGA/MDA/HGC", "EGA", "VGA" }; @@ -226,12 +228,16 @@ static int vga_probe(void) u8 vga_flag; asm(INT10 - : "=b" (boot_params.screen_info.orig_video_ega_bx) + : "=b" (ega_bx) : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */ : "ecx", "edx", "esi", "edi"); +#ifndef _WAKEUP + boot_params.screen_info.orig_video_ega_bx = ega_bx; +#endif + /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ - if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) { + if ((u8)ega_bx != 0x10) { /* EGA/VGA */ asm(INT10 : "=a" (vga_flag) @@ -240,7 +246,9 @@ static int vga_probe(void) if (vga_flag == 0x1a) { adapter = ADAPTER_VGA; +#ifndef _WAKEUP boot_params.screen_info.orig_video_isVGA = 1; +#endif } else { adapter = ADAPTER_EGA; } diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c index ad9712f..71be615 100644 --- a/arch/x86/boot/video.c +++ b/arch/x86/boot/video.c @@ -18,21 +18,6 @@ #include "boot.h" #include "video.h" #include "vesa.h" -/* - * Mode list variables - */ -static struct card_info cards[]; /* List of cards to probe for */ - -/* - * Common variables - */ -int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */ -u16 video_segment; -int force_x, force_y; /* Don't query the BIOS for cols/rows */ - -int do_restore = 0; /* Screen contents changed during mode flip */ -int graphic_mode; /* Graphic mode with linear frame buffer */ - static void store_cursor_position(void) { u16 curpos; @@ -107,147 +92,6 @@ static void store_mode_params(void) boot_params.screen_info.orig_video_lines = y; } -/* Probe the video drivers and have them generate their mode lists. */ -static void probe_cards(int unsafe) -{ - struct card_info *card; - static u8 probed[2]; - - if (probed[unsafe]) - return; - - probed[unsafe] = 1; - - for (card = video_cards; card < video_cards_end; card++) { - if (card->unsafe == unsafe) { - if (card->probe) - card->nmodes = card->probe(); - else - card->nmodes = 0; - } - } -} - -/* Test if a mode is defined */ -int mode_defined(u16 mode) -{ - struct card_info *card; - struct mode_info *mi; - int i; - - for (card = video_cards; card < video_cards_end; card++) { - mi = card->modes; - for (i = 0; i < card->nmodes; i++, mi++) { - if (mi->mode == mode) - return 1; - } - } - - return 0; -} - -/* Set mode (without recalc) */ -static int raw_set_mode(u16 mode, u16 *real_mode) -{ - int nmode, i; - struct card_info *card; - struct mode_info *mi; - - /* Drop the recalc bit if set */ - mode &= ~VIDEO_RECALC; - - /* Scan for mode based on fixed ID, position, or resolution */ - nmode = 0; - for (card = video_cards; card < video_cards_end; card++) { - mi = card->modes; - for (i = 0; i < card->nmodes; i++, mi++) { - int visible = mi->x || mi->y; - - if ((mode == nmode && visible) || - mode == mi->mode || - mode == (mi->y << 8)+mi->x) { - *real_mode = mi->mode; - return card->set_mode(mi); - } - - if (visible) - nmode++; - } - } - - /* Nothing found? Is it an "exceptional" (unprobed) mode? */ - for (card = video_cards; card < video_cards_end; card++) { - if (mode >= card->xmode_first && - mode < card->xmode_first+card->xmode_n) { - struct mode_info mix; - *real_mode = mix.mode = mode; - mix.x = mix.y = 0; - return card->set_mode(&mix); - } - } - - /* Otherwise, failure... */ - return -1; -} - -/* - * Recalculate the vertical video cutoff (hack!) - */ -static void vga_recalc_vertical(void) -{ - unsigned int font_size, rows; - u16 crtc; - u8 pt, ov; - - set_fs(0); - font_size = rdfs8(0x485); /* BIOS: font size (pixels) */ - rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */ - - rows *= font_size; /* Visible scan lines */ - rows--; /* ... minus one */ - - crtc = vga_crtc(); - - pt = in_idx(crtc, 0x11); - pt &= ~0x80; /* Unlock CR0-7 */ - out_idx(pt, crtc, 0x11); - - out_idx((u8)rows, crtc, 0x12); /* Lower height register */ - - ov = in_idx(crtc, 0x07); /* Overflow register */ - ov &= 0xbd; - ov |= (rows >> (8-1)) & 0x02; - ov |= (rows >> (9-6)) & 0x40; - out_idx(ov, crtc, 0x07); -} - -/* Set mode (with recalc if specified) */ -static int set_mode(u16 mode) -{ - int rv; - u16 real_mode; - - /* Very special mode numbers... */ - if (mode == VIDEO_CURRENT_MODE) - return 0; /* Nothing to do... */ - else if (mode == NORMAL_VGA) - mode = VIDEO_80x25; - else if (mode == EXTENDED_VGA) - mode = VIDEO_8POINT; - - rv = raw_set_mode(mode, &real_mode); - if (rv) - return rv; - - if (mode & VIDEO_RECALC) - vga_recalc_vertical(); - - /* Save the canonical mode number for the kernel, not - an alias, size specification or menu position */ - boot_params.hdr.vid_mode = real_mode; - return 0; -} - static unsigned int get_entry(void) { char entry_buf[4]; diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile index 19d3d6e..c617050 100644 --- a/arch/x86/kernel/acpi/Makefile +++ b/arch/x86/kernel/acpi/Makefile @@ -1,7 +1,14 @@ +subdir- := rm + obj-$(CONFIG_ACPI) += boot.o -obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_rm.o wakeup_$(BITS).o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += cstate.o processor.o endif +$(obj)/wakeup_rm.o: $(obj)/rm/wakeup.bin + +$(obj)/rm/wakeup.bin: FORCE + $(Q)$(MAKE) $(build)=$(obj)/rm $@ + diff --git a/arch/x86/kernel/acpi/rm/Makefile b/arch/x86/kernel/acpi/rm/Makefile new file mode 100644 index 0000000..2eb0e90 --- /dev/null +++ b/arch/x86/kernel/acpi/rm/Makefile @@ -0,0 +1,55 @@ +# +# arch/x86/kernel/acpi/rm/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +targets := wakeup.bin wakeup.elf + +wakeup-y += wakeup.o wakemain.o video-mode.o copy.o + +# The link order of the video-*.o modules can matter. In particular, +# video-vga.o *must* be listed first, followed by video-vesa.o. +# Hardware-specific drivers should follow in the order they should be +# probed, and video-bios.o should typically be last. +wakeup-y += video-vga.o +wakeup-y += video-vesa.o +wakeup-y += video-bios.o + +targets += $(wakeup-y) + +bootsrc := $(src)/../../../boot + +# --------------------------------------------------------------------------- + +# How to compile the 16-bit code. Note we always compile for -march=i386, +# that way we can complain to the user if the CPU is insufficient. +# Compile with _SETUP since this is similar to the boot-time setup code. +cflags-$(CONFIG_X86_32) := +cflags-$(CONFIG_X86_64) := -m32 +KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \ + -I$(srctree)/$(bootsrc) \ + $(cflags-y) \ + -Wall -Wstrict-prototypes \ + -march=i386 -mregparm=3 \ + -include $(srctree)/$(bootsrc)/code16gcc.h \ + -fno-strict-aliasing -fomit-frame-pointer \ + $(call cc-option, -ffreestanding) \ + $(call cc-option, -fno-toplevel-reorder,\ + $(call cc-option, -fno-unit-at-a-time)) \ + $(call cc-option, -fno-stack-protector) \ + $(call cc-option, -mpreferred-stack-boundary=2) +KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ + +WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y)) + +LDFLAGS_wakeup.elf := -T +$(obj)/wakeup.elf: $(src)/wakeup.ld $(WAKEUP_OBJS) FORCE + $(call if_changed,ld) + +OBJCOPYFLAGS_wakeup.bin := -O binary + +$(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE + $(call if_changed,objcopy) diff --git a/arch/x86/kernel/acpi/rm/copy.S b/arch/x86/kernel/acpi/rm/copy.S new file mode 100644 index 0000000..dc59ebe --- /dev/null +++ b/arch/x86/kernel/acpi/rm/copy.S @@ -0,0 +1 @@ +#include "../../../boot/copy.S" diff --git a/arch/x86/kernel/acpi/rm/video-bios.c b/arch/x86/kernel/acpi/rm/video-bios.c new file mode 100644 index 0000000..7deabc1 --- /dev/null +++ b/arch/x86/kernel/acpi/rm/video-bios.c @@ -0,0 +1 @@ +#include "../../../boot/video-bios.c" diff --git a/arch/x86/kernel/acpi/rm/video-mode.c b/arch/x86/kernel/acpi/rm/video-mode.c new file mode 100644 index 0000000..328ad20 --- /dev/null +++ b/arch/x86/kernel/acpi/rm/video-mode.c @@ -0,0 +1 @@ +#include "../../../boot/video-mode.c" diff --git a/arch/x86/kernel/acpi/rm/video-vesa.c b/arch/x86/kernel/acpi/rm/video-vesa.c new file mode 100644 index 0000000..9dbb967 --- /dev/null +++ b/arch/x86/kernel/acpi/rm/video-vesa.c @@ -0,0 +1 @@ +#include "../../../boot/video-vesa.c" diff --git a/arch/x86/kernel/acpi/rm/video-vga.c b/arch/x86/kernel/acpi/rm/video-vga.c new file mode 100644 index 0000000..bcc8125 --- /dev/null +++ b/arch/x86/kernel/acpi/rm/video-vga.c @@ -0,0 +1 @@ +#include "../../../boot/video-vga.c" diff --git a/arch/x86/kernel/acpi/rm/wakemain.c b/arch/x86/kernel/acpi/rm/wakemain.c new file mode 100644 index 0000000..d3173cc --- /dev/null +++ b/arch/x86/kernel/acpi/rm/wakemain.c @@ -0,0 +1,18 @@ +#include "wakeup.h" +#include "boot.h" + +extern struct wakeup_header wakeup_header; + +void main(void) +{ + asm volatile("lcallw $0xc000,$3; movw %cs, %ax; movw %ax, %ds; movw %ax, %es; movw %ax, %ss"); + +// asm volatile("inb $97, %al; outb %al, $0x80; movb $3, %al; outb %al, $97; outb %al, $0x80; movb $-74, %al; outb %al, $67; outb %al, $0x80; movb $-119, %al; outb %al, $66; outb %al, $0x80; movb $15, %al; outb %al, $66"); + + /* Need to call BIOS */ + probe_cards(0); +// set_mode(wakeup_header.video_mode); + set_mode(6); + + /* Set up GDT and IDT here, possibly CR4 and EFER */ +} diff --git a/arch/x86/kernel/acpi/rm/wakeup.S b/arch/x86/kernel/acpi/rm/wakeup.S new file mode 100644 index 0000000..bfa348c --- /dev/null +++ b/arch/x86/kernel/acpi/rm/wakeup.S @@ -0,0 +1,129 @@ +/* + * ACPI wakeup real mode startup stub + */ +#include <asm/segment.h> +#include <asm/msr-index.h> + + +#define BEEP \ + inb $97, %al; \ + outb %al, $0x80; \ + movb $3, %al; \ + outb %al, $97; \ + outb %al, $0x80; \ + movb $-74, %al; \ + outb %al, $67; \ + outb %al, $0x80; \ + movb $-119, %al; \ + outb %al, $66; \ + outb %al, $0x80; \ + movb $15, %al; \ + outb %al, $66; + + + .code16 + .section ".header", "a" + +/* This should match the structure in wakeup.h */ + .globl wakeup_header +wakeup_header: +entry: .short _start /* Offset of the entry point (== IP) */ +total: .short _end /* How much memory we want total, with bss */ +video_mode: .short 0 /* Video mode number */ +pmode_return: .byte 0x66, 0xea /* ljmpl */ + .long 0 /* offset goes here */ + .short __KERNEL_CS +pmode_cr0: .long 0 /* Saved %cr0 */ +pmode_cr3: .long 0 /* Saved %cr3 */ +pmode_cr4: .long 0 /* Saved %cr4 */ +pmode_efer: .quad 0 /* Saved EFER */ +pmode_gdt: .quad 0 +signature: .long 0x51ee1111 +real_magic: .long 0 + + + .text + .globl _start + .code16 +_start: + cli + cld + + /* Set up segments */ + movw %cs,%ax + movw %ax,%ds + movw %ax,%es + movw %ax,%ss + + movw $wakeup_stack_end, %sp + + /* Clear the EFLAGS */ + pushl $0 + popfl + + /* Check header signature... */ + movl signature, %eax + cmpl $0x51ee1111, %eax + jne bogus_real_magic + + /* Check we really have everything... */ + movl end_signature, %eax + cmpl $0x65a22c82, %eax + jne bogus_real_magic + + /* Zero the bss */ + xorl %eax, %eax + movw $__bss_start, %di + movw $__bss_end+3, %cx + subw %di, %cx + shrw $2, %cx + rep; stosl + + /* Call the C code */ + calll main + + /* Do any other stuff... */ + + /* This could also be done in C code... */ + movl pmode_cr3, %eax + movl %eax, %cr3 + + movl pmode_cr4, %ecx + jecxz 1f + movl %ecx, %cr4 +1: + movl pmode_efer, %eax + movl pmode_efer+4, %edx + movl %eax, %ecx + orl %edx, %ecx + jz 1f + movl $0xc0000080, %ecx + wrmsr +1: + + lgdtl pmode_gdt + + /* This really couldn't... */ + movl pmode_cr0, %eax + movl %eax, %cr0 + jmp pmode_return + +bogus_real_magic: +1: + hlt + jmp 1b + + .data + .balign 4 + .globl HEAP, heap_end +HEAP: + .long wakeup_heap +heap_end: + .long wakeup_stack + + .bss +wakeup_heap: + .space 2048 +wakeup_stack: + .space 2048 +wakeup_stack_end: diff --git a/arch/x86/kernel/acpi/rm/wakeup.h b/arch/x86/kernel/acpi/rm/wakeup.h new file mode 100644 index 0000000..c65087f --- /dev/null +++ b/arch/x86/kernel/acpi/rm/wakeup.h @@ -0,0 +1,29 @@ +/* + * Definitions for the wakeup data structure at the head of the + * wakeup code. + */ + +#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H +#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H + +#include <linux/types.h> + +/* This must match data at wakeup.S */ +struct wakeup_header { + u16 entry; /* 16-bit entry point */ + u16 total; /* Total number of bytes consumed */ + u16 video_mode; /* Video mode number */ + u16 _jmp1; + u32 pmode_entry; /* Protected mode resume point */ + u16 _jmp2; + u32 pmode_cr0; /* Protected mode cr0 */ + u32 pmode_cr3; /* Protected mode cr3 */ + u32 pmode_cr4; /* Protected mode cr4 */ + u32 pmode_efer_low; /* Protected mode EFER */ + u32 pmode_efer_high; + u64 pmode_gdt; + u32 signature; /* To check we have correct structure */ + u32 real_magic; +} __attribute__((__packed__)); + +#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */ diff --git a/arch/x86/kernel/acpi/rm/wakeup.ld b/arch/x86/kernel/acpi/rm/wakeup.ld new file mode 100644 index 0000000..bbe8d07 --- /dev/null +++ b/arch/x86/kernel/acpi/rm/wakeup.ld @@ -0,0 +1,50 @@ +/* + * wakeup.ld + * + * Linker script for the real-mode wakeup code + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0x3f00; + .header : { *(.header) } + + . = 0; + .text : { *(.text*) } + + . = ALIGN(16); + .rodata : { *(.rodata*) } + + .videocards : { + video_cards = .; + *(.videocards) + video_cards_end = .; + } + + . = ALIGN(16); + .data : { *(.data*) } + + .signature : { + end_signature = .; + LONG(0x65a22c82) + } + + . = ALIGN(16); + .bss : + { + __bss_start = .; + *(.bss) + __bss_end = .; + } + . = ALIGN(16); + _end = .; + + /DISCARD/ : { *(.note*) } + + /* Adjust this as appropriate */ + /* This allows 4 pages (16K) */ + . = ASSERT(_end <= 0x4000, "Wakeup too big!"); +} diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 26db0c1..cda1fa9 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -11,11 +11,13 @@ #include <linux/dmi.h> #include <linux/cpumask.h> #include <asm/smp.h> +#include "rm/wakeup.h" /* address in low memory of the wakeup routine. */ -unsigned long acpi_wakeup_address = 0; +static unsigned long acpi_realmode; +unsigned long acpi_wakeup_address; unsigned long acpi_realmode_flags; -extern char wakeup_start, wakeup_end; +extern char wakeup_code_start, wakeup_code_end; extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); @@ -24,16 +26,52 @@ extern unsigned long FASTCALL(acpi_copy_ * * Create an identity mapped page table and copy the wakeup routine to * low memory. + * + * Note that this is too late to change acpi_wakeup_address. */ int acpi_save_state_mem(void) { - if (!acpi_wakeup_address) { + printk("acpi_save_state_mem\n"); + if (!acpi_realmode) { printk(KERN_ERR "Could not allocate memory during boot, S3 disabled\n"); return -ENOMEM; } - memcpy((void *)acpi_wakeup_address, &wakeup_start, - &wakeup_end - &wakeup_start); - acpi_copy_wakeup_routine(acpi_wakeup_address); + memcpy((void *)acpi_realmode, &wakeup_code_start, 4*PAGE_SIZE); + { + struct wakeup_header *header = acpi_realmode + 0x3f00; + extern unsigned long saved_videomode; + + if (header->signature != 0x51ee1111) { + printk(KERN_ERR "wakeup header does not match\n"); + return -EINVAL; + } + + header->video_mode = saved_videomode; + /* FIXME: more setup needed, see acpi_copy_wakeup_routine() */ + + header->pmode_efer_low = nx_enabled; + if (header->pmode_efer_low & 1) { + /* This is strange, why not save efer, always? */ + rdmsr(MSR_EFER, header->pmode_efer_low, header->pmode_efer_high); + } + header->pmode_cr0 = read_cr0(); +// header->pmode_cr3 = read_cr3(); + + extern char swsusp_pg_dir[PAGE_SIZE]; + header->pmode_cr3 = swsusp_pg_dir - __PAGE_OFFSET; + header->pmode_cr4 = read_cr4(); + + store_gdt(&header->pmode_gdt); + +// header->realmode_flags = acpi_realmode_flags; + header->real_magic = 0x12345678; + + extern int wakeup_pmode_return; + header->pmode_entry = &wakeup_pmode_return; + + extern long saved_magic; + saved_magic = 0x12345678; + } return 0; } @@ -56,15 +94,20 @@ void acpi_restore_state_mem(void) */ void __init acpi_reserve_bootmem(void) { - if ((&wakeup_end - &wakeup_start) > PAGE_SIZE*2) { + if ((&wakeup_code_end - &wakeup_code_start) > PAGE_SIZE*4) { printk(KERN_ERR "ACPI: Wakeup code way too big, S3 disabled.\n"); return; } - acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2); - if (!acpi_wakeup_address) + acpi_realmode = (unsigned long)alloc_bootmem_low(PAGE_SIZE*4); + + if (!acpi_realmode) { printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); + return; + } + + acpi_wakeup_address = acpi_realmode; } diff --git a/arch/x86/kernel/acpi/wakeup.S b/arch/x86/kernel/acpi/wakeup.S index 38205c8..ba20316 100644 --- a/arch/x86/kernel/acpi/wakeup.S +++ b/arch/x86/kernel/acpi/wakeup.S @@ -15,97 +15,4 @@ #define BEEP \ movb $15, %al; \ outb %al, $66; -ALIGN - .align 4096 -ENTRY(wakeup_start) -wakeup_code: - wakeup_code_start = . - .code16 - cli - cld - - # setup data segment - movw %cs, %ax - movw %ax, %ds # Make ds:0 point to wakeup_start - movw %ax, %ss - - testl $4, realmode_flags - wakeup_code - jz 1f - BEEP -1: - mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board - - pushl $0 # Kill any dangerous flags - popfl - - - movl real_magic - wakeup_code, %eax - cmpl $0x12345678, %eax - jne bogus_real_magic - - testl $1, realmode_flags - wakeup_code - jz 1f - lcall $0xc000,$3 - movw %cs, %ax - movw %ax, %ds # Bios might have played with that - movw %ax, %ss -1: - - testl $2, realmode_flags - wakeup_code - jz mode_done - mov video_mode - wakeup_code, %ax - call mode_set - jmp mode_done - -/* This code uses an extended set of video mode numbers. These include: - * Aliases for standard modes - * NORMAL_VGA (-1) - * EXTENDED_VGA (-2) - * ASK_VGA (-3) - * Video modes numbered by menu position -- NOT RECOMMENDED because of lack - * of compatibility when extending the table. These are between 0x00 and 0xff. - */ -#define VIDEO_FIRST_MENU 0x0000 - -/* Standard BIOS video modes (BIOS number + 0x0100) */ -#define VIDEO_FIRST_BIOS 0x0100 - -/* VESA BIOS video modes (VESA number + 0x0200) */ -#define VIDEO_FIRST_VESA 0x0200 - -/* Video7 special modes (BIOS number + 0x0900) */ -#define VIDEO_FIRST_V7 0x0900 - -# Setting of user mode (AX=mode ID) => CF=success - -# For now, we only handle VESA modes (0x0200..0x03ff). To handle other -# modes, we should probably compile in the video code from the boot -# directory. -.code16 -mode_set: - movw %ax, %bx - subb $VIDEO_FIRST_VESA>>8, %bh - cmpb $2, %bh - jb check_vesa - -setbad: - clc - ret - -check_vesa: - orw $0x4000, %bx # Use linear frame buffer - movw $0x4f02, %ax # VESA BIOS mode set call - int $0x10 - cmpw $0x004f, %ax # AL=4f if implemented - jnz setbad # AH=0 if OK - - stc - ret - -bogus_real_magic: - jmp bogus_real_magic - -real_magic: .quad 0 -video_mode: .quad 0 -realmode_flags: .quad 0 diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S index 9b26909..681cfc6 100644 --- a/arch/x86/kernel/acpi/wakeup_32.S +++ b/arch/x86/kernel/acpi/wakeup_32.S @@ -7,63 +7,13 @@ # Copyright 2003, 2008 Pavel Machek <pav #include "wakeup.S" -mode_done: - # set up page table - movl $swsusp_pg_dir-__PAGE_OFFSET, %eax - movl %eax, %cr3 - - testl $1, real_efer_save_restore - wakeup_code - jz 4f - # restore efer setting - movl real_save_efer_edx - wakeup_code, %edx - movl real_save_efer_eax - wakeup_code, %eax - mov $0xc0000080, %ecx - wrmsr -4: - # make sure %cr4 is set correctly (features, etc) - movl real_save_cr4 - wakeup_code, %eax - movl %eax, %cr4 - - # need a gdt -- use lgdtl to force 32-bit operands, in case - # the GDT is located past 16 megabytes. - lgdtl real_save_gdt - wakeup_code - - movl real_save_cr0 - wakeup_code, %eax - movl %eax, %cr0 - jmp 1f -1: - movl real_magic - wakeup_code, %eax - cmpl $0x12345678, %eax - jne bogus_real_magic - - testl $8, realmode_flags - wakeup_code - jz 1f - BEEP -1: - ljmpl $__KERNEL_CS, $wakeup_pmode_return - -real_save_gdt: .word 0 - .long 0 -real_save_cr0: .long 0 -real_save_cr3: .long 0 -real_save_cr4: .long 0 -real_efer_save_restore: .long 0 -real_save_efer_edx: .long 0 -real_save_efer_eax: .long 0 - .code32 ALIGN -.org 0x800 -wakeup_stack_begin: # Stack grows down - -.org 0xff0 # Just below end of page -wakeup_stack: -ENTRY(wakeup_end) - -.org 0x1000 - +ENTRY(wakeup_pmode_return) wakeup_pmode_return: + BEEP + movw $__KERNEL_DS, %ax movw %ax, %ss movw %ax, %ds @@ -96,56 +46,13 @@ bogus_magic: jmp bogus_magic -## -# acpi_copy_wakeup_routine -# -# Copy the above routine to low memory. -# -# Parameters: -# %eax: place to copy wakeup routine to -# -# Returned address is location of code in low memory (past data and stack) -# -ENTRY(acpi_copy_wakeup_routine) - pushl %ebx +save_registers: sgdt saved_gdt sidt saved_idt sldt saved_ldt str saved_tss - - movl nx_enabled, %edx - movl %edx, real_efer_save_restore - wakeup_start (%eax) - testl $1, real_efer_save_restore - wakeup_start (%eax) - jz 2f - # save efer setting - pushl %eax - movl %eax, %ebx - mov $0xc0000080, %ecx - rdmsr - movl %edx, real_save_efer_edx - wakeup_start (%ebx) - movl %eax, real_save_efer_eax - wakeup_start (%ebx) - popl %eax -2: - - movl %cr3, %edx - movl %edx, real_save_cr3 - wakeup_start (%eax) - movl %cr4, %edx - movl %edx, real_save_cr4 - wakeup_start (%eax) - movl %cr0, %edx - movl %edx, real_save_cr0 - wakeup_start (%eax) - sgdt real_save_gdt - wakeup_start (%eax) - - movl saved_videomode, %edx - movl %edx, video_mode - wakeup_start (%eax) - movl acpi_realmode_flags, %edx - movl %edx, realmode_flags - wakeup_start (%eax) - movl $0x12345678, real_magic - wakeup_start (%eax) - movl $0x12345678, saved_magic - popl %ebx - ret - -save_registers: + leal 4(%esp), %eax movl %eax, saved_context_esp movl %ebx, saved_context_ebx diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index b02d97f..2d5a868 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -181,10 +181,10 @@ ENTRY(wakeup_end) ## # acpi_copy_wakeup_routine # -# Copy the above routine to low memory. +# Name is misleading, copy is actually done in C, this just fixups it. # # Parameters: -# %rdi: place to copy wakeup routine to +# %rdi: place to fixup wakeup routine at # # Returned address is location of code in low memory (past data and stack) # @@ -209,7 +209,6 @@ ENTRY(acpi_copy_wakeup_routine) # restore the regs we used popq %rdx popq %rax -ENTRY(do_suspend_lowlevel_s4bios) ret .align 2 diff --git a/arch/x86/kernel/acpi/wakeup_rm.S b/arch/x86/kernel/acpi/wakeup_rm.S new file mode 100644 index 0000000..17e2dc1 --- /dev/null +++ b/arch/x86/kernel/acpi/wakeup_rm.S @@ -0,0 +1,10 @@ +/* + * Wrapper script for the realmode binary as a transport object + * before copying to low memory. + */ + .section ".rodata","a" + .globl wakeup_code_start, wakeup_code_end +wakeup_code_start: + .incbin "arch/x86/kernel/acpi/rm/wakeup.bin" +wakeup_code_end: + .size wakeup_code_start, .-wakeup_code_start diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 2c0b663..0ab6da1 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -139,7 +139,7 @@ static int acpi_pm_enter(suspend_state_t break; } - /* ACPI 3.0 specs (P62) says that it's the responsabilty + /* ACPI 3.0 specs (P62) says that it's the responsibilty * of the OSPM to clear the status bit [ implying that the * POWER_BUTTON event should not reach userspace ] */ -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: factor out common s2ram wakeup code 2008-01-25 23:12 ` Pavel Machek @ 2008-01-25 23:36 ` H. Peter Anvin 0 siblings, 0 replies; 9+ messages in thread From: H. Peter Anvin @ 2008-01-25 23:36 UTC (permalink / raw) To: Pavel Machek; +Cc: kernel list, Linux-pm mailing list, Rafael J. Wysocki Pavel Machek wrote: > diff --git a/arch/x86/kernel/acpi/rm/wakemain.c b/arch/x86/kernel/acpi/rm/wakemain.c > new file mode 100644 > index 0000000..d3173cc > --- /dev/null > +++ b/arch/x86/kernel/acpi/rm/wakemain.c > @@ -0,0 +1,18 @@ > +#include "wakeup.h" > +#include "boot.h" > + > +extern struct wakeup_header wakeup_header; > + > +void main(void) > +{ > + asm volatile("lcallw $0xc000,$3; movw %cs, %ax; movw %ax, %ds; movw %ax, %es; movw %ax, %ss"); > + > +// asm volatile("inb $97, %al; outb %al, $0x80; movb $3, %al; outb %al, $97; outb %al, $0x80; movb $-74, %al; outb %al, $67; outb %al, $0x80; movb $-119, %al; outb %al, $66; outb %al, $0x80; movb $15, %al; outb %al, $66"); > + > + /* Need to call BIOS */ > + probe_cards(0); > +// set_mode(wakeup_header.video_mode); > + set_mode(6); > + > + /* Set up GDT and IDT here, possibly CR4 and EFER */ > +} Surely this needs some cleaning up? ;) > diff --git a/arch/x86/kernel/acpi/rm/wakeup.S b/arch/x86/kernel/acpi/rm/wakeup.S > new file mode 100644 > index 0000000..bfa348c > --- /dev/null > +++ b/arch/x86/kernel/acpi/rm/wakeup.S > @@ -0,0 +1,129 @@ > +/* > + * ACPI wakeup real mode startup stub > + */ > +#include <asm/segment.h> > +#include <asm/msr-index.h> > + > + > +#define BEEP \ > + inb $97, %al; \ > + outb %al, $0x80; \ > + movb $3, %al; \ > + outb %al, $97; \ > + outb %al, $0x80; \ > + movb $-74, %al; \ > + outb %al, $67; \ > + outb %al, $0x80; \ > + movb $-119, %al; \ > + outb %al, $66; \ > + outb %al, $0x80; \ > + movb $15, %al; \ > + outb %al, $66; > + BEEP isn't actually used here and should probably be a C function if needed. Note: in real mode you can also produce a beep by calling int $0x10 with %ax = 0x0e07. Please note that some int $0x10 implementations clobber certain registers... see the INT10 macro in the bootup code. Seriously cool, though, that you're getting this far. -hpa ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: factor out common s2ram wakeup code 2008-01-22 19:37 factor out common s2ram wakeup code Pavel Machek 2008-01-22 20:27 ` H. Peter Anvin @ 2008-01-24 0:20 ` Rafael J. Wysocki 1 sibling, 0 replies; 9+ messages in thread From: Rafael J. Wysocki @ 2008-01-24 0:20 UTC (permalink / raw) To: Pavel Machek; +Cc: kernel list, mingo, tglx, hpa On Tuesday, 22 of January 2008, Pavel Machek wrote: > > It seems to compile 32/64bit, and work 32bit... It also works on a 64-bit system. Thanks, Rafael > --- > > Factor out common real-mode part of wakeup_{32,64}.S. > > Signed-off-by: Pavel Machek <pavel@suse.cz> > > --- > commit 2fac1886274433c64e76611e6b1ba2318c5914a4 > tree 2d6bdc7c2eda9845b57e1d7128b187df1b1fd2c9 > parent 7a9546efcc4d90040a52c003eb9a303200c41f86 > author Pavel <pavel@amd.ucw.cz> Tue, 22 Jan 2008 20:34:03 +0100 > committer Pavel <pavel@amd.ucw.cz> Tue, 22 Jan 2008 20:34:03 +0100 > > arch/x86/kernel/acpi/wakeup.S | 111 ++++++++++++++++++++++++++++++++++ > arch/x86/kernel/acpi/wakeup_32.S | 118 +----------------------------------- > arch/x86/kernel/acpi/wakeup_64.S | 125 +------------------------------------- > 3 files changed, 116 insertions(+), 238 deletions(-) > > diff --git a/arch/x86/kernel/acpi/wakeup.S b/arch/x86/kernel/acpi/wakeup.S > new file mode 100644 > index 0000000..38205c8 > --- /dev/null > +++ b/arch/x86/kernel/acpi/wakeup.S > @@ -0,0 +1,111 @@ > +# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2 > + > +#define BEEP \ > + inb $97, %al; \ > + outb %al, $0x80; \ > + movb $3, %al; \ > + outb %al, $97; \ > + outb %al, $0x80; \ > + movb $-74, %al; \ > + outb %al, $67; \ > + outb %al, $0x80; \ > + movb $-119, %al; \ > + outb %al, $66; \ > + outb %al, $0x80; \ > + movb $15, %al; \ > + outb %al, $66; > + > +ALIGN > + .align 4096 > +ENTRY(wakeup_start) > +wakeup_code: > + wakeup_code_start = . > + .code16 > + > + cli > + cld > + > + # setup data segment > + movw %cs, %ax > + movw %ax, %ds # Make ds:0 point to wakeup_start > + movw %ax, %ss > + > + testl $4, realmode_flags - wakeup_code > + jz 1f > + BEEP > +1: > + mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board > + > + pushl $0 # Kill any dangerous flags > + popfl > + > + > + movl real_magic - wakeup_code, %eax > + cmpl $0x12345678, %eax > + jne bogus_real_magic > + > + testl $1, realmode_flags - wakeup_code > + jz 1f > + lcall $0xc000,$3 > + movw %cs, %ax > + movw %ax, %ds # Bios might have played with that > + movw %ax, %ss > +1: > + > + testl $2, realmode_flags - wakeup_code > + jz mode_done > + mov video_mode - wakeup_code, %ax > + call mode_set > + jmp mode_done > + > +/* This code uses an extended set of video mode numbers. These include: > + * Aliases for standard modes > + * NORMAL_VGA (-1) > + * EXTENDED_VGA (-2) > + * ASK_VGA (-3) > + * Video modes numbered by menu position -- NOT RECOMMENDED because of lack > + * of compatibility when extending the table. These are between 0x00 and 0xff. > + */ > +#define VIDEO_FIRST_MENU 0x0000 > + > +/* Standard BIOS video modes (BIOS number + 0x0100) */ > +#define VIDEO_FIRST_BIOS 0x0100 > + > +/* VESA BIOS video modes (VESA number + 0x0200) */ > +#define VIDEO_FIRST_VESA 0x0200 > + > +/* Video7 special modes (BIOS number + 0x0900) */ > +#define VIDEO_FIRST_V7 0x0900 > + > +# Setting of user mode (AX=mode ID) => CF=success > + > +# For now, we only handle VESA modes (0x0200..0x03ff). To handle other > +# modes, we should probably compile in the video code from the boot > +# directory. > +.code16 > +mode_set: > + movw %ax, %bx > + subb $VIDEO_FIRST_VESA>>8, %bh > + cmpb $2, %bh > + jb check_vesa > + > +setbad: > + clc > + ret > + > +check_vesa: > + orw $0x4000, %bx # Use linear frame buffer > + movw $0x4f02, %ax # VESA BIOS mode set call > + int $0x10 > + cmpw $0x004f, %ax # AL=4f if implemented > + jnz setbad # AH=0 if OK > + > + stc > + ret > + > +bogus_real_magic: > + jmp bogus_real_magic > + > +real_magic: .quad 0 > +video_mode: .quad 0 > +realmode_flags: .quad 0 > diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S > index 1e931aa..9b26909 100644 > --- a/arch/x86/kernel/acpi/wakeup_32.S > +++ b/arch/x86/kernel/acpi/wakeup_32.S > @@ -3,73 +3,11 @@ #include <linux/linkage.h> > #include <asm/segment.h> > #include <asm/page.h> > > -# > -# wakeup_code runs in real mode, and at unknown address (determined at run-time). > -# Therefore it must only use relative jumps/calls. > -# > -# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled > -# > -# If physical address of wakeup_code is 0x12345, BIOS should call us with > -# cs = 0x1234, eip = 0x05 > -# > - > -#define BEEP \ > - inb $97, %al; \ > - outb %al, $0x80; \ > - movb $3, %al; \ > - outb %al, $97; \ > - outb %al, $0x80; \ > - movb $-74, %al; \ > - outb %al, $67; \ > - outb %al, $0x80; \ > - movb $-119, %al; \ > - outb %al, $66; \ > - outb %al, $0x80; \ > - movb $15, %al; \ > - outb %al, $66; > - > -ALIGN > - .align 4096 > -ENTRY(wakeup_start) > -wakeup_code: > - wakeup_code_start = . > - .code16 > - > - cli > - cld > - > - # setup data segment > - movw %cs, %ax > - movw %ax, %ds # Make ds:0 point to wakeup_start > - movw %ax, %ss > - > - testl $4, realmode_flags - wakeup_code > - jz 1f > - BEEP > -1: > - mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board > +# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2 > > - pushl $0 # Kill any dangerous flags > - popfl > - > - movl real_magic - wakeup_code, %eax > - cmpl $0x12345678, %eax > - jne bogus_real_magic > - > - testl $1, realmode_flags - wakeup_code > - jz 1f > - lcall $0xc000,$3 > - movw %cs, %ax > - movw %ax, %ds # Bios might have played with that > - movw %ax, %ss > -1: > - > - testl $2, realmode_flags - wakeup_code > - jz 1f > - mov video_mode - wakeup_code, %ax > - call mode_set > -1: > +#include "wakeup.S" > > +mode_done: > # set up page table > movl $swsusp_pg_dir-__PAGE_OFFSET, %eax > movl %eax, %cr3 > @@ -109,60 +47,10 @@ real_save_gdt: .word 0 > real_save_cr0: .long 0 > real_save_cr3: .long 0 > real_save_cr4: .long 0 > -real_magic: .long 0 > -video_mode: .long 0 > -realmode_flags: .long 0 > real_efer_save_restore: .long 0 > real_save_efer_edx: .long 0 > real_save_efer_eax: .long 0 > > -bogus_real_magic: > - jmp bogus_real_magic > - > -/* This code uses an extended set of video mode numbers. These include: > - * Aliases for standard modes > - * NORMAL_VGA (-1) > - * EXTENDED_VGA (-2) > - * ASK_VGA (-3) > - * Video modes numbered by menu position -- NOT RECOMMENDED because of lack > - * of compatibility when extending the table. These are between 0x00 and 0xff. > - */ > -#define VIDEO_FIRST_MENU 0x0000 > - > -/* Standard BIOS video modes (BIOS number + 0x0100) */ > -#define VIDEO_FIRST_BIOS 0x0100 > - > -/* VESA BIOS video modes (VESA number + 0x0200) */ > -#define VIDEO_FIRST_VESA 0x0200 > - > -/* Video7 special modes (BIOS number + 0x0900) */ > -#define VIDEO_FIRST_V7 0x0900 > - > -# Setting of user mode (AX=mode ID) => CF=success > - > -# For now, we only handle VESA modes (0x0200..0x03ff). To handle other > -# modes, we should probably compile in the video code from the boot > -# directory. > -mode_set: > - movw %ax, %bx > - subb $VIDEO_FIRST_VESA>>8, %bh > - cmpb $2, %bh > - jb check_vesa > - > -setbad: > - clc > - ret > - > -check_vesa: > - orw $0x4000, %bx # Use linear frame buffer > - movw $0x4f02, %ax # VESA BIOS mode set call > - int $0x10 > - cmpw $0x004f, %ax # AL=4f if implemented > - jnz setbad # AH=0 if OK > - > - stc > - ret > - > .code32 > ALIGN > > diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S > index 5ed3bc5..b02d97f 100644 > --- a/arch/x86/kernel/acpi/wakeup_64.S > +++ b/arch/x86/kernel/acpi/wakeup_64.S > @@ -7,78 +7,10 @@ #include <asm/msr.h> > #include <asm/asm-offsets.h> > > # Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2 > -# > -# wakeup_code runs in real mode, and at unknown address (determined at run-time). > -# Therefore it must only use relative jumps/calls. > -# > -# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled > -# > -# If physical address of wakeup_code is 0x12345, BIOS should call us with > -# cs = 0x1234, eip = 0x05 > -# > - > -#define BEEP \ > - inb $97, %al; \ > - outb %al, $0x80; \ > - movb $3, %al; \ > - outb %al, $97; \ > - outb %al, $0x80; \ > - movb $-74, %al; \ > - outb %al, $67; \ > - outb %al, $0x80; \ > - movb $-119, %al; \ > - outb %al, $66; \ > - outb %al, $0x80; \ > - movb $15, %al; \ > - outb %al, $66; > - > - > -ALIGN > - .align 16 > -ENTRY(wakeup_start) > -wakeup_code: > - wakeup_code_start = . > - .code16 > - > -# Running in *copy* of this code, somewhere in low 1MB. > - > - cli > - cld > - # setup data segment > - movw %cs, %ax > - movw %ax, %ds # Make ds:0 point to wakeup_start > - movw %ax, %ss > - > - # Data segment must be set up before we can see whether to beep. > - testl $4, realmode_flags - wakeup_code > - jz 1f > - BEEP > -1: > - > - # Private stack is needed for ASUS board > - mov $(wakeup_stack - wakeup_code), %sp > - > - pushl $0 # Kill any dangerous flags > - popfl > > - movl real_magic - wakeup_code, %eax > - cmpl $0x12345678, %eax > - jne bogus_real_magic > - > - testl $1, realmode_flags - wakeup_code > - jz 1f > - lcall $0xc000,$3 > - movw %cs, %ax > - movw %ax, %ds # Bios might have played with that > - movw %ax, %ss > -1: > - > - testl $2, realmode_flags - wakeup_code > - jz 1f > - mov video_mode - wakeup_code, %ax > - call mode_set > -1: > +#include "wakeup.S" > > +mode_done: > mov %ds, %ax # Find 32bit wakeup_code addr > movzx %ax, %esi # (Convert %ds:gdt to a liner ptr) > shll $4, %esi > @@ -227,64 +159,11 @@ gdt_48a: > .word 0x800 # gdt limit=2048, > # 256 GDT entries > .long gdta - wakeup_code # gdt base (relocated in later) > - > -real_magic: .quad 0 > -video_mode: .quad 0 > -realmode_flags: .quad 0 > - > -.code16 > -bogus_real_magic: > - jmp bogus_real_magic > > .code64 > bogus_64_magic: > jmp bogus_64_magic > > -/* This code uses an extended set of video mode numbers. These include: > - * Aliases for standard modes > - * NORMAL_VGA (-1) > - * EXTENDED_VGA (-2) > - * ASK_VGA (-3) > - * Video modes numbered by menu position -- NOT RECOMMENDED because of lack > - * of compatibility when extending the table. These are between 0x00 and 0xff. > - */ > -#define VIDEO_FIRST_MENU 0x0000 > - > -/* Standard BIOS video modes (BIOS number + 0x0100) */ > -#define VIDEO_FIRST_BIOS 0x0100 > - > -/* VESA BIOS video modes (VESA number + 0x0200) */ > -#define VIDEO_FIRST_VESA 0x0200 > - > -/* Video7 special modes (BIOS number + 0x0900) */ > -#define VIDEO_FIRST_V7 0x0900 > - > -# Setting of user mode (AX=mode ID) => CF=success > - > -# For now, we only handle VESA modes (0x0200..0x03ff). To handle other > -# modes, we should probably compile in the video code from the boot > -# directory. > -.code16 > -mode_set: > - movw %ax, %bx > - subb $VIDEO_FIRST_VESA>>8, %bh > - cmpb $2, %bh > - jb check_vesa > - > -setbad: > - clc > - ret > - > -check_vesa: > - orw $0x4000, %bx # Use linear frame buffer > - movw $0x4f02, %ax # VESA BIOS mode set call > - int $0x10 > - cmpw $0x004f, %ax # AL=4f if implemented > - jnz setbad # AH=0 if OK > - > - stc > - ret > - > wakeup_stack_begin: # Stack grows down > > .org 0xff0 > -- "Premature optimization is the root of all evil." - Donald Knuth ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-01-25 23:37 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-22 19:37 factor out common s2ram wakeup code Pavel Machek
2008-01-22 20:27 ` H. Peter Anvin
[not found] ` <20080122205625.GC4317@elf.ucw.cz>
[not found] ` <47965B13.9080705@zytor.com>
2008-01-22 21:24 ` Pavel Machek
2008-01-22 21:51 ` H. Peter Anvin
2008-01-22 22:03 ` Pavel Machek
2008-01-22 22:09 ` H. Peter Anvin
[not found] ` <47969BB2.2020409@zytor.com>
2008-01-25 23:12 ` Pavel Machek
2008-01-25 23:36 ` H. Peter Anvin
2008-01-24 0:20 ` Rafael J. Wysocki
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox