* 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
* 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
* 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
* 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
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