LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [rft] s2ram wakeup moves to .c, could fix few machines
@ 2008-02-05 19:06 Pavel Machek
  2008-02-06  1:27 ` Rafael J. Wysocki
  2008-02-06 23:37 ` Rafael J. Wysocki
  0 siblings, 2 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-05 19:06 UTC (permalink / raw)
  To: kernel list, Linux-pm mailing list, Rafael J. Wysocki, H. Peter Anvin


This rewrites wakeup code to .c, and it fixes stack (should use movl
,%esp, not movw). Testers wanted. Makefile infrastructure was done by
hpa, cleanups by rjw.

Signed-off-by: Pavel Machek <pavel@suse.cz>

diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 8978e98..949b8eb 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -192,8 +192,8 @@ drivers-$(CONFIG_PCI)            += arch
 # must be linked after kernel/
 drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/
 
-ifeq ($(CONFIG_X86_32),y)
 drivers-$(CONFIG_PM) += arch/x86/power/
+ifeq ($(CONFIG_X86_32),y)
 drivers-$(CONFIG_FB) += arch/x86/video/
 endif
 
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 349b81a..0a5bcd3 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -30,7 +30,7 @@ subdir- 	:= compressed
 
 setup-y		+= a20.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
+setup-y		+= printf.o string.o tty.o video.o video-mode.o version.o
 setup-$(CONFIG_X86_APM_BOOT) += apm.o
 setup-$(CONFIG_X86_VOYAGER) += voyager.o
 
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index 7822a49..0957807 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -286,6 +286,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 ff664a1..39e247e 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 662dd2f..f5cd4c1 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -160,7 +160,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;
@@ -187,6 +189,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;
@@ -196,8 +199,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)
 {
@@ -290,6 +296,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 7259387..330d658 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 696d08f..c1c47ba 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];
@@ -486,6 +330,7 @@ void set_video(void)
 		printf("Undefined video mode number: %x\n", mode);
 		mode = ASK_VGA;
 	}
+	boot_params.hdr.vid_mode = mode;
 	vesa_store_edid();
 	store_mode_params();
 
diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile
index 19d3d6e..aff42de 100644
--- a/arch/x86/kernel/acpi/Makefile
+++ b/arch/x86/kernel/acpi/Makefile
@@ -1,7 +1,14 @@
+subdir-				:= realmode
+
 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)/realmode/wakeup.bin
+       
+$(obj)/realmode/wakeup.bin: FORCE
+	$(Q)$(MAKE) $(build)=$(obj)/realmode $@
+
diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile
new file mode 100644
index 0000000..2eb0e90
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/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/realmode/copy.S b/arch/x86/kernel/acpi/realmode/copy.S
new file mode 100644
index 0000000..dc59ebe
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/copy.S
@@ -0,0 +1 @@
+#include "../../../boot/copy.S"
diff --git a/arch/x86/kernel/acpi/realmode/video-bios.c b/arch/x86/kernel/acpi/realmode/video-bios.c
new file mode 100644
index 0000000..7deabc1
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/video-bios.c
@@ -0,0 +1 @@
+#include "../../../boot/video-bios.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-mode.c b/arch/x86/kernel/acpi/realmode/video-mode.c
new file mode 100644
index 0000000..328ad20
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/video-mode.c
@@ -0,0 +1 @@
+#include "../../../boot/video-mode.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-vesa.c b/arch/x86/kernel/acpi/realmode/video-vesa.c
new file mode 100644
index 0000000..9dbb967
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/video-vesa.c
@@ -0,0 +1 @@
+#include "../../../boot/video-vesa.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-vga.c b/arch/x86/kernel/acpi/realmode/video-vga.c
new file mode 100644
index 0000000..bcc8125
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/video-vga.c
@@ -0,0 +1 @@
+#include "../../../boot/video-vga.c"
diff --git a/arch/x86/kernel/acpi/realmode/wakemain.c b/arch/x86/kernel/acpi/realmode/wakemain.c
new file mode 100644
index 0000000..10673aa
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakemain.c
@@ -0,0 +1,26 @@
+#include "wakeup.h"
+#include "boot.h"
+
+extern volatile struct wakeup_header wakeup_header;
+
+void main(void)
+{
+	/* Kill machine if structures are wrong */
+	if (wakeup_header.real_magic != 0x12345678)
+		while(1);
+
+	if (wakeup_header.realmode_flags & 4) {
+		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");
+	}
+
+	if (wakeup_header.realmode_flags & 1) {
+		asm volatile("lcallw   $0xc000,$3");
+//		("movw    %cs, %ax;	movw    %ax, %ds;	movw	%ax, %es; movw    %ax, %ss");
+	}
+
+	if (wakeup_header.realmode_flags & 2) {
+		/* Need to call BIOS */
+		probe_cards(0);
+		set_mode(wakeup_header.video_mode);
+	}
+}
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S
new file mode 100644
index 0000000..bddceb9
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakeup.S
@@ -0,0 +1,124 @@
+/*
+ * ACPI wakeup real mode startup stub
+ */
+#include <asm/segment.h>
+#include <asm/msr-index.h>
+#include <asm/page_64.h>
+#include <asm/pgtable_64.h>
+
+	.code16
+	.section ".header", "a"
+
+/* This should match the structure in wakeup.h */
+		.globl	wakeup_header
+wakeup_header:
+entry:		.short	_start	/* unused */
+total:		.short	_end	/* unused */
+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
+realmode_flags:	.long	0
+real_magic:	.long	0
+trampoline_segment:	.word 0
+signature:	.long	0x51ee1111
+
+	.text
+	.globl	_start
+	.code16
+wakeup_code:
+_start:
+	cli
+	cld
+
+	/* Set up segments */
+	movw	%cs,%ax
+	movw	%ax,%ds
+	movw	%ax,%es
+	movw	%ax,%ss
+
+	movl	$wakeup_stack_end, %esp
+
+	/* 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... */
+	
+#ifndef CONFIG_64BIT
+	/* 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
+#else
+	pushw	$0
+	pushw	trampoline_segment
+	pushw	$0
+	lret	
+#endif
+
+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/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h
new file mode 100644
index 0000000..4a26e27
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakeup.h
@@ -0,0 +1,31 @@
+/*
+ * 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;		/* unused */
+	u16 total;		/* unused */
+	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 realmode_flags;
+	u32 real_magic;
+	u16 trampoline_segment;
+	u32 signature;		/* To check we have correct structure */
+} __attribute__((__packed__));
+
+#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.ld b/arch/x86/kernel/acpi/realmode/wakeup.ld
new file mode 100644
index 0000000..5dff2f0
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakeup.ld
@@ -0,0 +1,51 @@
+/*
+ * 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 6bc815c..1b282b1 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -11,29 +11,84 @@ #include <linux/dmi.h>
 #include <linux/cpumask.h>
 
 #include <asm/smp.h>
+#include "realmode/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 acpi_copy_wakeup_routine(unsigned long);
+extern unsigned long setup_trampoline(void);
+extern void wakeup_long64(void);
+
+extern unsigned long saved_video_mode;
+extern long saved_magic;
+extern volatile unsigned long init_rsp;
+extern void (*initial_code)(void);
+#ifndef CONFIG_64BIT
+extern int wakeup_pmode_return;
+extern char swsusp_pg_dir[PAGE_SIZE];
+#else
+static char temp_stack[10240];
+#endif
+
+extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
 
 /**
  * acpi_save_state_mem - save kernel state
  *
  * 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(KERN_ERR "Could not allocate memory during boot, S3 disabled\n");
+	struct wakeup_header *header;
+
+	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);
+
+	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
+	if (header->signature != 0x51ee1111) {
+		printk(KERN_ERR "wakeup header does not match\n");
+		return -EINVAL;
+	}
+
+	header->video_mode = saved_video_mode;
+
+#ifndef CONFIG_64BIT
+	store_gdt(&header->pmode_gdt);
+
+	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);
+	}
+#endif /* !CONFIG_64BIT */
+
+	header->pmode_cr0 = read_cr0();
+	header->pmode_cr4 = read_cr4();
+	header->realmode_flags = acpi_realmode_flags;
+	header->real_magic = 0x12345678;
+
+#ifndef CONFIG_64BIT
+	header->pmode_entry = &wakeup_pmode_return;
+	header->pmode_cr3 = swsusp_pg_dir - __PAGE_OFFSET;
+	saved_magic = 0x12345678;
+#else /* CONFIG_64BIT */
+	header->trampoline_segment = setup_trampoline() >> 4;
+	init_rsp = (unsigned long)temp_stack + 4096;
+	initial_code = wakeup_long64;
+	saved_magic = 0x123456789abcdef0;
+#endif /* CONFIG_64BIT */
 
 	return 0;
 }
@@ -56,15 +111,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
new file mode 100644
index 0000000..6157603
--- /dev/null
+++ b/arch/x86/kernel/acpi/wakeup.S
@@ -0,0 +1 @@
+# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S
index f53e327..ca9cac2 100644
--- a/arch/x86/kernel/acpi/wakeup_32.S
+++ b/arch/x86/kernel/acpi/wakeup_32.S
@@ -3,178 +3,14 @@ #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
-#
+# 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	1f
-	mov	video_mode - wakeup_code, %ax
-	call	mode_set
-1:
-
-	# 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_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
+#include "wakeup.S"
 
 	.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:
 	movw	$__KERNEL_DS, %ax
 	movw	%ax, %ss
@@ -208,56 +44,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 2e1b9e0..7be7609 100644
--- a/arch/x86/kernel/acpi/wakeup_64.S
+++ b/arch/x86/kernel/acpi/wakeup_64.S
@@ -7,191 +7,23 @@ #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;
+#include "wakeup.S"
 
-
-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:
-
-	mov	%ds, %ax			# Find 32bit wakeup_code addr
-	movzx   %ax, %esi			# (Convert %ds:gdt to a liner ptr)
-	shll    $4, %esi
-						# Fix up the vectors
-	addl    %esi, wakeup_32_vector - wakeup_code
-	addl    %esi, wakeup_long64_vector - wakeup_code
-	addl    %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
-
-	lidtl	%ds:idt_48a - wakeup_code
-	lgdtl	%ds:gdt_48a - wakeup_code	# load gdt with whatever is
-						# appropriate
-
-	movl	$1, %eax			# protected mode (PE) bit
-	lmsw	%ax				# This is it!
-	jmp	1f
-1:
-
-	ljmpl   *(wakeup_32_vector - wakeup_code)
-
-	.balign 4
-wakeup_32_vector:
-	.long   wakeup_32 - wakeup_code
-	.word   __KERNEL32_CS, 0
-
-	.code32
-wakeup_32:
 # Running in this code, but at low address; paging is not yet turned on.
 
-	movl	$__KERNEL_DS, %eax
-	movl	%eax, %ds
-
-	/*
-	 * Prepare for entering 64bits mode
-	 */
-
-	/* Enable PAE */
-	xorl	%eax, %eax
-	btsl	$5, %eax
-	movl	%eax, %cr4
-
-	/* Setup early boot stage 4 level pagetables */
-	leal    (wakeup_level4_pgt - wakeup_code)(%esi), %eax
-	movl	%eax, %cr3
-
-        /* Check if nx is implemented */
-        movl    $0x80000001, %eax
-        cpuid
-        movl    %edx,%edi
-
-	/* Enable Long Mode */
-	xorl    %eax, %eax
-	btsl	$_EFER_LME, %eax
-
-	/* No Execute supported? */
-	btl	$20,%edi
-	jnc     1f
-	btsl	$_EFER_NX, %eax
-				
-	/* Make changes effective */
-1:	movl    $MSR_EFER, %ecx
-	xorl    %edx, %edx
-	wrmsr
-
-	xorl	%eax, %eax
-	btsl	$31, %eax			/* Enable paging and in turn activate Long Mode */
-	btsl	$0, %eax			/* Enable protected mode */
-
-	/* Make changes effective */
-	movl	%eax, %cr0
-
-	/* At this point:
-		CR4.PAE must be 1
-		CS.L must be 0
-		CR3 must point to PML4
-		Next instruction must be a branch
-		This must be on identity-mapped page
-	*/
-	/*
-	 * At this point we're in long mode but in 32bit compatibility mode
-	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
-	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
-	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
-	 */
-
-	/* Finally jump in 64bit mode */
-        ljmp    *(wakeup_long64_vector - wakeup_code)(%esi)
-
-	.balign 4
-wakeup_long64_vector:
-	.long   wakeup_long64 - wakeup_code
-	.word   __KERNEL_CS, 0
-
 .code64
 
 	/* Hooray, we are in Long 64-bit mode (but still running in
 	 * low memory)
 	 */
+ENTRY(wakeup_long64)
 wakeup_long64:
-	/*
-	 * We must switch to a new descriptor in kernel space for the GDT
-	 * because soon the kernel won't have access anymore to the userspace
-	 * addresses where we're currently running on. We have to do that here
-	 * because in 32bit we couldn't load a 64bit linear address.
-	 */
-	lgdt	cpu_gdt_descr
-
 	movq    saved_magic, %rax
 	movq    $0x123456789abcdef0, %rdx
 	cmpq    %rdx, %rax
 	jne     bogus_64_magic
 
-	nop
-	nop
 	movw	$__KERNEL_DS, %ax
 	movw	%ax, %ss	
 	movw	%ax, %ds
@@ -208,131 +40,9 @@ wakeup_long64:
 	movq	saved_rip, %rax
 	jmp	*%rax
 
-.code32
-
-	.align	64	
-gdta:
-	/* Its good to keep gdt in sync with one in trampoline.S */
-	.word	0, 0, 0, 0			# dummy
-	/* ??? Why I need the accessed bit set in order for this to work? */
-	.quad   0x00cf9b000000ffff              # __KERNEL32_CS
-	.quad   0x00af9b000000ffff              # __KERNEL_CS
-	.quad   0x00cf93000000ffff              # __KERNEL_DS
-
-idt_48a:
-	.word	0				# idt limit = 0
-	.word	0, 0				# idt base = 0L
-
-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
-wakeup_stack:		# Just below end of page
-
-.org   0x1000
-ENTRY(wakeup_level4_pgt)
-	.quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
-	.fill   510,8,0
-	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
-	.quad   level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
-
-ENTRY(wakeup_end)
-	
-##
-# acpi_copy_wakeup_routine
-#
-# Copy the above routine to low memory.
-#
-# Parameters:
-# %rdi:	place to copy wakeup routine to
-#
-# Returned address is location of code in low memory (past data and stack)
-#
-	.code64
-ENTRY(acpi_copy_wakeup_routine)
-	pushq	%rax
-	pushq	%rdx
-
-	movl	saved_video_mode, %edx
-	movl	%edx, video_mode - wakeup_start (,%rdi)
-	movl	acpi_realmode_flags, %edx
-	movl	%edx, realmode_flags - wakeup_start (,%rdi)
-	movq	$0x12345678, real_magic - wakeup_start (,%rdi)
-	movq	$0x123456789abcdef0, %rdx
-	movq	%rdx, saved_magic
-
-	movq    saved_magic, %rax
-	movq    $0x123456789abcdef0, %rdx
-	cmpq    %rdx, %rax
-	jne     bogus_64_magic
-
-	# restore the regs we used
-	popq	%rdx
-	popq	%rax
-ENTRY(do_suspend_lowlevel_s4bios)
-	ret
-
 	.align 2
 	.p2align 4,,15
 .globl do_suspend_lowlevel
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/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 1d5a7a3..668bcfb 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -127,10 +127,6 @@ #ifdef CONFIG_SMP
 	addq	%rbp, trampoline_level4_pgt + 0(%rip)
 	addq	%rbp, trampoline_level4_pgt + (511*8)(%rip)
 #endif
-#ifdef CONFIG_ACPI_SLEEP
-	addq	%rbp, wakeup_level4_pgt + 0(%rip)
-	addq	%rbp, wakeup_level4_pgt + (511*8)(%rip)
-#endif
 
 	/* Due to ENTRY(), sometimes the empty space gets filled with
 	 * zeros. Better take a jmp than relying on empty space being
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index 62adc5f..da5f631 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -186,7 +186,7 @@ #endif
 extern void early_cpu_init(void);
 extern int root_mountflags;
 
-unsigned long saved_videomode;
+unsigned long saved_video_mode;
 
 #define RAMDISK_IMAGE_START_MASK	0x07FF
 #define RAMDISK_PROMPT_FLAG		0x8000
@@ -711,7 +711,7 @@ #endif
 	edid_info = boot_params.edid_info;
 	apm_info.bios = boot_params.apm_bios_info;
 	ist_info = boot_params.ist_info;
-	saved_videomode = boot_params.hdr.vid_mode;
+	saved_video_mode = boot_params.hdr.vid_mode;
 	if( boot_params.sys_desc_table.length != 0 ) {
 		set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2);
 		machine_id = boot_params.sys_desc_table.table[0];
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index d53bd6f..ebb038e 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -132,7 +132,7 @@ #endif
  * has made sure it's suitably aligned.
  */
 
-static unsigned long __cpuinit setup_trampoline(void)
+unsigned long __cpuinit setup_trampoline(void)
 {
 	void *tramp = __va(SMP_TRAMPOLINE_BASE); 
 	memcpy(tramp, trampoline_data, trampoline_end - trampoline_data);
@@ -649,6 +649,9 @@ do_rest:
 	*((volatile unsigned short *) phys_to_virt(0x467)) = start_rip & 0xf;
 	Dprintk("3.\n");
 
+	/* Trampoline assumes it is at beggining of segment */
+	BUG_ON(start_rip & 0xf);
+
 	/*
 	 * Be paranoid about clearing APIC errors.
 	 */
@@ -656,11 +659,6 @@ do_rest:
 	apic_read(APIC_ESR);
 
 	/*
-	 * Status is now clean
-	 */
-	boot_error = 0;
-
-	/*
 	 * Starting actual IPI sequence...
 	 */
 	boot_error = wakeup_secondary_via_INIT(apicid, start_rip);
diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S
new file mode 100644
index 0000000..d0f40d9
--- /dev/null
+++ b/arch/x86_64/kernel/acpi/wakeup.S
@@ -0,0 +1,425 @@
+.text
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/msr.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:
+
+	mov	%ds, %ax			# Find 32bit wakeup_code addr
+	movzx   %ax, %esi			# (Convert %ds:gdt to a liner ptr)
+	shll    $4, %esi
+						# Fix up the vectors
+	addl    %esi, wakeup_32_vector - wakeup_code
+	addl    %esi, wakeup_long64_vector - wakeup_code
+	addl    %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
+
+	lidtl	%ds:idt_48a - wakeup_code
+	lgdtl	%ds:gdt_48a - wakeup_code	# load gdt with whatever is
+						# appropriate
+
+	movl	$1, %eax			# protected mode (PE) bit
+	lmsw	%ax				# This is it!
+	jmp	1f
+1:
+
+	ljmpl   *(wakeup_32_vector - wakeup_code)
+
+	.balign 4
+wakeup_32_vector:
+	.long   wakeup_32 - wakeup_code
+	.word   __KERNEL32_CS, 0
+
+	.code32
+wakeup_32:
+# Running in this code, but at low address; paging is not yet turned on.
+
+	movl	$__KERNEL_DS, %eax
+	movl	%eax, %ds
+
+	/*
+	 * Prepare for entering 64bits mode
+	 */
+
+	/* Enable PAE */
+	xorl	%eax, %eax
+	btsl	$5, %eax
+	movl	%eax, %cr4
+
+	/* Setup early boot stage 4 level pagetables */
+	leal    (wakeup_level4_pgt - wakeup_code)(%esi), %eax
+	movl	%eax, %cr3
+
+        /* Check if nx is implemented */
+        movl    $0x80000001, %eax
+        cpuid
+        movl    %edx,%edi
+
+	/* Enable Long Mode */
+	xorl    %eax, %eax
+	btsl	$_EFER_LME, %eax
+
+	/* No Execute supported? */
+	btl	$20,%edi
+	jnc     1f
+	btsl	$_EFER_NX, %eax
+				
+	/* Make changes effective */
+1:	movl    $MSR_EFER, %ecx
+	xorl    %edx, %edx
+	wrmsr
+
+	xorl	%eax, %eax
+	btsl	$31, %eax			/* Enable paging and in turn activate Long Mode */
+	btsl	$0, %eax			/* Enable protected mode */
+
+	/* Make changes effective */
+	movl	%eax, %cr0
+
+	/* At this point:
+		CR4.PAE must be 1
+		CS.L must be 0
+		CR3 must point to PML4
+		Next instruction must be a branch
+		This must be on identity-mapped page
+	*/
+	/*
+	 * At this point we're in long mode but in 32bit compatibility mode
+	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
+	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
+	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+	 */
+
+	/* Finally jump in 64bit mode */
+        ljmp    *(wakeup_long64_vector - wakeup_code)(%esi)
+
+	.balign 4
+wakeup_long64_vector:
+	.long   wakeup_long64 - wakeup_code
+	.word   __KERNEL_CS, 0
+
+.code64
+
+	/* Hooray, we are in Long 64-bit mode (but still running in
+	 * low memory)
+	 */
+wakeup_long64:
+	/*
+	 * We must switch to a new descriptor in kernel space for the GDT
+	 * because soon the kernel won't have access anymore to the userspace
+	 * addresses where we're currently running on. We have to do that here
+	 * because in 32bit we couldn't load a 64bit linear address.
+	 */
+	lgdt	cpu_gdt_descr
+
+	movq    saved_magic, %rax
+	movq    $0x123456789abcdef0, %rdx
+	cmpq    %rdx, %rax
+	jne     bogus_64_magic
+
+	nop
+	nop
+	movw	$__KERNEL_DS, %ax
+	movw	%ax, %ss	
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+	movq	saved_rsp, %rsp
+
+	movq	saved_rbx, %rbx
+	movq	saved_rdi, %rdi
+	movq	saved_rsi, %rsi
+	movq	saved_rbp, %rbp
+
+	movq	saved_rip, %rax
+	jmp	*%rax
+
+.code32
+
+	.align	64	
+gdta:
+	/* Its good to keep gdt in sync with one in trampoline.S */
+	.word	0, 0, 0, 0			# dummy
+	/* ??? Why I need the accessed bit set in order for this to work? */
+	.quad   0x00cf9b000000ffff              # __KERNEL32_CS
+	.quad   0x00af9b000000ffff              # __KERNEL_CS
+	.quad   0x00cf93000000ffff              # __KERNEL_DS
+
+idt_48a:
+	.word	0				# idt limit = 0
+	.word	0, 0				# idt base = 0L
+
+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
+wakeup_stack:		# Just below end of page
+
+.org   0x1000
+ENTRY(wakeup_level4_pgt)
+	.quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+	.fill   510,8,0
+	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
+	.quad   level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
+
+ENTRY(wakeup_end)
+	
+##
+# acpi_copy_wakeup_routine
+#
+# Copy the above routine to low memory.
+#
+# Parameters:
+# %rdi:	place to copy wakeup routine to
+#
+# Returned address is location of code in low memory (past data and stack)
+#
+	.code64
+ENTRY(acpi_copy_wakeup_routine)
+	pushq	%rax
+	pushq	%rdx
+
+	movl	saved_video_mode, %edx
+	movl	%edx, video_mode - wakeup_start (,%rdi)
+	movl	acpi_realmode_flags, %edx
+	movl	%edx, realmode_flags - wakeup_start (,%rdi)
+	movq	$0x12345678, real_magic - wakeup_start (,%rdi)
+	movq	$0x123456789abcdef0, %rdx
+	movq	%rdx, saved_magic
+
+	movq    saved_magic, %rax
+	movq    $0x123456789abcdef0, %rdx
+	cmpq    %rdx, %rax
+	jne     bogus_64_magic
+
+	# restore the regs we used
+	popq	%rdx
+	popq	%rax
+ENTRY(do_suspend_lowlevel_s4bios)
+	ret
+
+	.align 2
+	.p2align 4,,15
+.globl do_suspend_lowlevel
+	.type	do_suspend_lowlevel,@function
+do_suspend_lowlevel:
+.LFB5:
+	subq	$8, %rsp
+	xorl	%eax, %eax
+	call	save_processor_state
+
+	movq %rsp, saved_context_esp(%rip)
+	movq %rax, saved_context_eax(%rip)
+	movq %rbx, saved_context_ebx(%rip)
+	movq %rcx, saved_context_ecx(%rip)
+	movq %rdx, saved_context_edx(%rip)
+	movq %rbp, saved_context_ebp(%rip)
+	movq %rsi, saved_context_esi(%rip)
+	movq %rdi, saved_context_edi(%rip)
+	movq %r8,  saved_context_r08(%rip)
+	movq %r9,  saved_context_r09(%rip)
+	movq %r10, saved_context_r10(%rip)
+	movq %r11, saved_context_r11(%rip)
+	movq %r12, saved_context_r12(%rip)
+	movq %r13, saved_context_r13(%rip)
+	movq %r14, saved_context_r14(%rip)
+	movq %r15, saved_context_r15(%rip)
+	pushfq ; popq saved_context_eflags(%rip)
+
+	movq	$.L97, saved_rip(%rip)
+
+	movq %rsp,saved_rsp
+	movq %rbp,saved_rbp
+	movq %rbx,saved_rbx
+	movq %rdi,saved_rdi
+	movq %rsi,saved_rsi
+
+	addq	$8, %rsp
+	movl	$3, %edi
+	xorl	%eax, %eax
+	jmp	acpi_enter_sleep_state
+.L97:
+	.p2align 4,,7
+.L99:
+	.align 4
+	movl	$24, %eax
+	movw %ax, %ds
+	movq	saved_context+58(%rip), %rax
+	movq %rax, %cr4
+	movq	saved_context+50(%rip), %rax
+	movq %rax, %cr3
+	movq	saved_context+42(%rip), %rax
+	movq %rax, %cr2
+	movq	saved_context+34(%rip), %rax
+	movq %rax, %cr0
+	pushq saved_context_eflags(%rip) ; popfq
+	movq saved_context_esp(%rip), %rsp
+	movq saved_context_ebp(%rip), %rbp
+	movq saved_context_eax(%rip), %rax
+	movq saved_context_ebx(%rip), %rbx
+	movq saved_context_ecx(%rip), %rcx
+	movq saved_context_edx(%rip), %rdx
+	movq saved_context_esi(%rip), %rsi
+	movq saved_context_edi(%rip), %rdi
+	movq saved_context_r08(%rip), %r8
+	movq saved_context_r09(%rip), %r9
+	movq saved_context_r10(%rip), %r10
+	movq saved_context_r11(%rip), %r11
+	movq saved_context_r12(%rip), %r12
+	movq saved_context_r13(%rip), %r13
+	movq saved_context_r14(%rip), %r14
+	movq saved_context_r15(%rip), %r15
+
+	xorl	%eax, %eax
+	addq	$8, %rsp
+	jmp	restore_processor_state
+.LFE5:
+.Lfe5:
+	.size	do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel
+	
+.data
+ALIGN
+ENTRY(saved_rbp)	.quad	0
+ENTRY(saved_rsi)	.quad	0
+ENTRY(saved_rdi)	.quad	0
+ENTRY(saved_rbx)	.quad	0
+
+ENTRY(saved_rip)	.quad	0
+ENTRY(saved_rsp)	.quad	0
+
+ENTRY(saved_magic)	.quad	0
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 485de13..56e09cf 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -170,7 +170,7 @@ static int acpi_pm_enter(suspend_state_t
 	/* Reprogram control registers and execute _BFS */
 	acpi_leave_sleep_state_prep(acpi_state);
 
-	/* 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	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-05 19:06 [rft] s2ram wakeup moves to .c, could fix few machines Pavel Machek
@ 2008-02-06  1:27 ` Rafael J. Wysocki
  2008-02-06  1:36   ` H. Peter Anvin
  2008-02-06 23:48   ` Rafael J. Wysocki
  2008-02-06 23:37 ` Rafael J. Wysocki
  1 sibling, 2 replies; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-06  1:27 UTC (permalink / raw)
  To: Pavel Machek; +Cc: kernel list, Linux-pm mailing list, H. Peter Anvin

On Tuesday, 5 of February 2008, Pavel Machek wrote:
> 
> This rewrites wakeup code to .c, and it fixes stack (should use movl
> ,%esp, not movw). Testers wanted. Makefile infrastructure was done by
> hpa, cleanups by rjw.

I'll test it tomorrow and I still have some more cleanups (I was distracted by
a nasty scheduler issue in the current mainline).

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-06  1:27 ` Rafael J. Wysocki
@ 2008-02-06  1:36   ` H. Peter Anvin
  2008-02-06  1:42     ` Rafael J. Wysocki
  2008-02-06 23:48   ` Rafael J. Wysocki
  1 sibling, 1 reply; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-06  1:36 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

Rafael J. Wysocki wrote:
> On Tuesday, 5 of February 2008, Pavel Machek wrote:
>> This rewrites wakeup code to .c, and it fixes stack (should use movl
>> ,%esp, not movw). Testers wanted. Makefile infrastructure was done by
>> hpa, cleanups by rjw.
> 
> I'll test it tomorrow and I still have some more cleanups (I was distracted by
> a nasty scheduler issue in the current mainline).

The asm() for making beeps really need to be moved to a function and 
cleaned up (redone in C using inb()/outb()) if they are to be retained 
at all.

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-06  1:36   ` H. Peter Anvin
@ 2008-02-06  1:42     ` Rafael J. Wysocki
  2008-02-06  1:51       ` H. Peter Anvin
  0 siblings, 1 reply; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-06  1:42 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

On Wednesday, 6 of February 2008, H. Peter Anvin wrote:
> Rafael J. Wysocki wrote:
> > On Tuesday, 5 of February 2008, Pavel Machek wrote:
> >> This rewrites wakeup code to .c, and it fixes stack (should use movl
> >> ,%esp, not movw). Testers wanted. Makefile infrastructure was done by
> >> hpa, cleanups by rjw.
> > 
> > I'll test it tomorrow and I still have some more cleanups (I was distracted by
> > a nasty scheduler issue in the current mainline).
> 
> The asm() for making beeps really need to be moved to a function and 
> cleaned up (redone in C using inb()/outb()) if they are to be retained 
> at all.

Yes, they are.  For some people they're the only tool to debug broken resume.

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-06  1:42     ` Rafael J. Wysocki
@ 2008-02-06  1:51       ` H. Peter Anvin
  2008-02-06  1:56         ` Rafael J. Wysocki
                           ` (2 more replies)
  0 siblings, 3 replies; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-06  1:51 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

Rafael J. Wysocki wrote:
>> The asm() for making beeps really need to be moved to a function and 
>> cleaned up (redone in C using inb()/outb()) if they are to be retained 
>> at all.
> 
> Yes, they are.  For some people they're the only tool to debug broken resume.

That's fine, but they should get cleaned up.

/me is tempted to provide a version which can send messages in Morse Code ;)

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-06  1:51       ` H. Peter Anvin
@ 2008-02-06  1:56         ` Rafael J. Wysocki
  2008-02-06 11:29         ` Pavel Machek
  2008-02-14  2:54         ` Bill Davidsen
  2 siblings, 0 replies; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-06  1:56 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

On Wednesday, 6 of February 2008, H. Peter Anvin wrote:
> Rafael J. Wysocki wrote:
> >> The asm() for making beeps really need to be moved to a function and 
> >> cleaned up (redone in C using inb()/outb()) if they are to be retained 
> >> at all.
> > 
> > Yes, they are.  For some people they're the only tool to debug broken resume.
> 
> That's fine, but they should get cleaned up.

I 100% agree.

> /me is tempted to provide a version which can send messages in Morse Code ;)

That would be great.  It could also play some music or something. ;-)

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-06  1:51       ` H. Peter Anvin
  2008-02-06  1:56         ` Rafael J. Wysocki
@ 2008-02-06 11:29         ` Pavel Machek
  2008-02-14  2:54         ` Bill Davidsen
  2 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-06 11:29 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

On Tue 2008-02-05 17:51:22, H. Peter Anvin wrote:
> Rafael J. Wysocki wrote:
>>> The asm() for making beeps really need to be moved to a function and 
>>> cleaned up (redone in C using inb()/outb()) if they are to be retained at 
>>> all.
>>
>> Yes, they are.  For some people they're the only tool to debug broken resume.
>
> That's fine, but they should get cleaned up.
>
> /me is tempted to provide a version which can send messages in Morse Code ;)

Actually, it would probably be accepted. Debugging early resume is
evil enough that any help is welcome.
									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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-05 19:06 [rft] s2ram wakeup moves to .c, could fix few machines Pavel Machek
  2008-02-06  1:27 ` Rafael J. Wysocki
@ 2008-02-06 23:37 ` Rafael J. Wysocki
  1 sibling, 0 replies; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-06 23:37 UTC (permalink / raw)
  To: Pavel Machek; +Cc: kernel list, Linux-pm mailing list, H. Peter Anvin

On Tuesday, 5 of February 2008, Pavel Machek wrote:
> 
> This rewrites wakeup code to .c, and it fixes stack (should use movl
> ,%esp, not movw). Testers wanted. Makefile infrastructure was done by
> hpa, cleanups by rjw.
> 
> Signed-off-by: Pavel Machek <pavel@suse.cz>
> 
[--snip--]
> diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S
> new file mode 100644
> index 0000000..d0f40d9
> --- /dev/null
> +++ b/arch/x86_64/kernel/acpi/wakeup.S

Surely this is not intentional?

> @@ -0,0 +1,425 @@
> +.text
> +#include <linux/linkage.h>
> +#include <asm/segment.h>
> +#include <asm/pgtable.h>
> +#include <asm/page.h>
> +#include <asm/msr.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:
> +
> +	mov	%ds, %ax			# Find 32bit wakeup_code addr
> +	movzx   %ax, %esi			# (Convert %ds:gdt to a liner ptr)
> +	shll    $4, %esi
> +						# Fix up the vectors
> +	addl    %esi, wakeup_32_vector - wakeup_code
> +	addl    %esi, wakeup_long64_vector - wakeup_code
> +	addl    %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
> +
> +	lidtl	%ds:idt_48a - wakeup_code
> +	lgdtl	%ds:gdt_48a - wakeup_code	# load gdt with whatever is
> +						# appropriate
> +
> +	movl	$1, %eax			# protected mode (PE) bit
> +	lmsw	%ax				# This is it!
> +	jmp	1f
> +1:
> +
> +	ljmpl   *(wakeup_32_vector - wakeup_code)
> +
> +	.balign 4
> +wakeup_32_vector:
> +	.long   wakeup_32 - wakeup_code
> +	.word   __KERNEL32_CS, 0
> +
> +	.code32
> +wakeup_32:
> +# Running in this code, but at low address; paging is not yet turned on.
> +
> +	movl	$__KERNEL_DS, %eax
> +	movl	%eax, %ds
> +
> +	/*
> +	 * Prepare for entering 64bits mode
> +	 */
> +
> +	/* Enable PAE */
> +	xorl	%eax, %eax
> +	btsl	$5, %eax
> +	movl	%eax, %cr4
> +
> +	/* Setup early boot stage 4 level pagetables */
> +	leal    (wakeup_level4_pgt - wakeup_code)(%esi), %eax
> +	movl	%eax, %cr3
> +
> +        /* Check if nx is implemented */
> +        movl    $0x80000001, %eax
> +        cpuid
> +        movl    %edx,%edi
> +
> +	/* Enable Long Mode */
> +	xorl    %eax, %eax
> +	btsl	$_EFER_LME, %eax
> +
> +	/* No Execute supported? */
> +	btl	$20,%edi
> +	jnc     1f
> +	btsl	$_EFER_NX, %eax
> +				
> +	/* Make changes effective */
> +1:	movl    $MSR_EFER, %ecx
> +	xorl    %edx, %edx
> +	wrmsr
> +
> +	xorl	%eax, %eax
> +	btsl	$31, %eax			/* Enable paging and in turn activate Long Mode */
> +	btsl	$0, %eax			/* Enable protected mode */
> +
> +	/* Make changes effective */
> +	movl	%eax, %cr0
> +
> +	/* At this point:
> +		CR4.PAE must be 1
> +		CS.L must be 0
> +		CR3 must point to PML4
> +		Next instruction must be a branch
> +		This must be on identity-mapped page
> +	*/
> +	/*
> +	 * At this point we're in long mode but in 32bit compatibility mode
> +	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
> +	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
> +	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
> +	 */
> +
> +	/* Finally jump in 64bit mode */
> +        ljmp    *(wakeup_long64_vector - wakeup_code)(%esi)
> +
> +	.balign 4
> +wakeup_long64_vector:
> +	.long   wakeup_long64 - wakeup_code
> +	.word   __KERNEL_CS, 0
> +
> +.code64
> +
> +	/* Hooray, we are in Long 64-bit mode (but still running in
> +	 * low memory)
> +	 */
> +wakeup_long64:
> +	/*
> +	 * We must switch to a new descriptor in kernel space for the GDT
> +	 * because soon the kernel won't have access anymore to the userspace
> +	 * addresses where we're currently running on. We have to do that here
> +	 * because in 32bit we couldn't load a 64bit linear address.
> +	 */
> +	lgdt	cpu_gdt_descr
> +
> +	movq    saved_magic, %rax
> +	movq    $0x123456789abcdef0, %rdx
> +	cmpq    %rdx, %rax
> +	jne     bogus_64_magic
> +
> +	nop
> +	nop
> +	movw	$__KERNEL_DS, %ax
> +	movw	%ax, %ss	
> +	movw	%ax, %ds
> +	movw	%ax, %es
> +	movw	%ax, %fs
> +	movw	%ax, %gs
> +	movq	saved_rsp, %rsp
> +
> +	movq	saved_rbx, %rbx
> +	movq	saved_rdi, %rdi
> +	movq	saved_rsi, %rsi
> +	movq	saved_rbp, %rbp
> +
> +	movq	saved_rip, %rax
> +	jmp	*%rax
> +
> +.code32
> +
> +	.align	64	
> +gdta:
> +	/* Its good to keep gdt in sync with one in trampoline.S */
> +	.word	0, 0, 0, 0			# dummy
> +	/* ??? Why I need the accessed bit set in order for this to work? */
> +	.quad   0x00cf9b000000ffff              # __KERNEL32_CS
> +	.quad   0x00af9b000000ffff              # __KERNEL_CS
> +	.quad   0x00cf93000000ffff              # __KERNEL_DS
> +
> +idt_48a:
> +	.word	0				# idt limit = 0
> +	.word	0, 0				# idt base = 0L
> +
> +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
> +wakeup_stack:		# Just below end of page
> +
> +.org   0x1000
> +ENTRY(wakeup_level4_pgt)
> +	.quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
> +	.fill   510,8,0
> +	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
> +	.quad   level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
> +
> +ENTRY(wakeup_end)
> +	
> +##
> +# acpi_copy_wakeup_routine
> +#
> +# Copy the above routine to low memory.
> +#
> +# Parameters:
> +# %rdi:	place to copy wakeup routine to
> +#
> +# Returned address is location of code in low memory (past data and stack)
> +#
> +	.code64
> +ENTRY(acpi_copy_wakeup_routine)
> +	pushq	%rax
> +	pushq	%rdx
> +
> +	movl	saved_video_mode, %edx
> +	movl	%edx, video_mode - wakeup_start (,%rdi)
> +	movl	acpi_realmode_flags, %edx
> +	movl	%edx, realmode_flags - wakeup_start (,%rdi)
> +	movq	$0x12345678, real_magic - wakeup_start (,%rdi)
> +	movq	$0x123456789abcdef0, %rdx
> +	movq	%rdx, saved_magic
> +
> +	movq    saved_magic, %rax
> +	movq    $0x123456789abcdef0, %rdx
> +	cmpq    %rdx, %rax
> +	jne     bogus_64_magic
> +
> +	# restore the regs we used
> +	popq	%rdx
> +	popq	%rax
> +ENTRY(do_suspend_lowlevel_s4bios)
> +	ret
> +
> +	.align 2
> +	.p2align 4,,15
> +.globl do_suspend_lowlevel
> +	.type	do_suspend_lowlevel,@function
> +do_suspend_lowlevel:
> +.LFB5:
> +	subq	$8, %rsp
> +	xorl	%eax, %eax
> +	call	save_processor_state
> +
> +	movq %rsp, saved_context_esp(%rip)
> +	movq %rax, saved_context_eax(%rip)
> +	movq %rbx, saved_context_ebx(%rip)
> +	movq %rcx, saved_context_ecx(%rip)
> +	movq %rdx, saved_context_edx(%rip)
> +	movq %rbp, saved_context_ebp(%rip)
> +	movq %rsi, saved_context_esi(%rip)
> +	movq %rdi, saved_context_edi(%rip)
> +	movq %r8,  saved_context_r08(%rip)
> +	movq %r9,  saved_context_r09(%rip)
> +	movq %r10, saved_context_r10(%rip)
> +	movq %r11, saved_context_r11(%rip)
> +	movq %r12, saved_context_r12(%rip)
> +	movq %r13, saved_context_r13(%rip)
> +	movq %r14, saved_context_r14(%rip)
> +	movq %r15, saved_context_r15(%rip)
> +	pushfq ; popq saved_context_eflags(%rip)
> +
> +	movq	$.L97, saved_rip(%rip)
> +
> +	movq %rsp,saved_rsp
> +	movq %rbp,saved_rbp
> +	movq %rbx,saved_rbx
> +	movq %rdi,saved_rdi
> +	movq %rsi,saved_rsi
> +
> +	addq	$8, %rsp
> +	movl	$3, %edi
> +	xorl	%eax, %eax
> +	jmp	acpi_enter_sleep_state
> +.L97:
> +	.p2align 4,,7
> +.L99:
> +	.align 4
> +	movl	$24, %eax
> +	movw %ax, %ds
> +	movq	saved_context+58(%rip), %rax
> +	movq %rax, %cr4
> +	movq	saved_context+50(%rip), %rax
> +	movq %rax, %cr3
> +	movq	saved_context+42(%rip), %rax
> +	movq %rax, %cr2
> +	movq	saved_context+34(%rip), %rax
> +	movq %rax, %cr0
> +	pushq saved_context_eflags(%rip) ; popfq
> +	movq saved_context_esp(%rip), %rsp
> +	movq saved_context_ebp(%rip), %rbp
> +	movq saved_context_eax(%rip), %rax
> +	movq saved_context_ebx(%rip), %rbx
> +	movq saved_context_ecx(%rip), %rcx
> +	movq saved_context_edx(%rip), %rdx
> +	movq saved_context_esi(%rip), %rsi
> +	movq saved_context_edi(%rip), %rdi
> +	movq saved_context_r08(%rip), %r8
> +	movq saved_context_r09(%rip), %r9
> +	movq saved_context_r10(%rip), %r10
> +	movq saved_context_r11(%rip), %r11
> +	movq saved_context_r12(%rip), %r12
> +	movq saved_context_r13(%rip), %r13
> +	movq saved_context_r14(%rip), %r14
> +	movq saved_context_r15(%rip), %r15
> +
> +	xorl	%eax, %eax
> +	addq	$8, %rsp
> +	jmp	restore_processor_state
> +.LFE5:
> +.Lfe5:
> +	.size	do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel
> +	
> +.data
> +ALIGN
> +ENTRY(saved_rbp)	.quad	0
> +ENTRY(saved_rsi)	.quad	0
> +ENTRY(saved_rdi)	.quad	0
> +ENTRY(saved_rbx)	.quad	0
> +
> +ENTRY(saved_rip)	.quad	0
> +ENTRY(saved_rsp)	.quad	0
> +
> +ENTRY(saved_magic)	.quad	0
> diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
> index 485de13..56e09cf 100644
> --- a/drivers/acpi/sleep/main.c
> +++ b/drivers/acpi/sleep/main.c
> @@ -170,7 +170,7 @@ static int acpi_pm_enter(suspend_state_t
>  	/* Reprogram control registers and execute _BFS */
>  	acpi_leave_sleep_state_prep(acpi_state);
>  
> -	/* 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 ]
>  	 */
> 



-- 
"Premature optimization is the root of all evil." - Donald Knuth

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-06  1:27 ` Rafael J. Wysocki
  2008-02-06  1:36   ` H. Peter Anvin
@ 2008-02-06 23:48   ` Rafael J. Wysocki
  2008-02-07 22:12     ` Rafael J. Wysocki
  1 sibling, 1 reply; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-06 23:48 UTC (permalink / raw)
  To: Pavel Machek; +Cc: kernel list, Linux-pm mailing list, H. Peter Anvin

On Wednesday, 6 of February 2008, Rafael J. Wysocki wrote:
> On Tuesday, 5 of February 2008, Pavel Machek wrote:
> > 
> > This rewrites wakeup code to .c, and it fixes stack (should use movl
> > ,%esp, not movw). Testers wanted. Makefile infrastructure was done by
> > hpa, cleanups by rjw.
> 
> I'll test it tomorrow

Works on my nx6325 (good sign, the box is easy to break ;-)).

> and I still have some more cleanups (I was distracted by a nasty scheduler
> issue in the current mainline).

The cleanups are still in the works (sorry).

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-06 23:48   ` Rafael J. Wysocki
@ 2008-02-07 22:12     ` Rafael J. Wysocki
  2008-02-07 22:28       ` Sam Ravnborg
                         ` (2 more replies)
  0 siblings, 3 replies; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-07 22:12 UTC (permalink / raw)
  To: Pavel Machek; +Cc: kernel list, Linux-pm mailing list, H. Peter Anvin

On Thursday, 7 of February 2008, Rafael J. Wysocki wrote:
> On Wednesday, 6 of February 2008, Rafael J. Wysocki wrote:
> > On Tuesday, 5 of February 2008, Pavel Machek wrote:
> > > 
> > > This rewrites wakeup code to .c, and it fixes stack (should use movl
> > > ,%esp, not movw). Testers wanted. Makefile infrastructure was done by
> > > hpa, cleanups by rjw.
> > 
> > I'll test it tomorrow
> 
> Works on my nx6325 (good sign, the box is easy to break ;-)).
> 
> > and I still have some more cleanups (I was distracted by a nasty scheduler
> > issue in the current mainline).
> 
> The cleanups are still in the works (sorry).

Below is a version with some easy cleanups, rebased on top of the patches that
move the 64-bit hibernation code to arch/x86/power .

Thanks,
Rafael

---
 arch/x86/boot/Makefile                     |    2 
 arch/x86/boot/boot.h                       |    5 
 arch/x86/boot/video-bios.c                 |    6 
 arch/x86/boot/video-mode.c                 |  173 ++++++++++++++++
 arch/x86/boot/video-vesa.c                 |    8 
 arch/x86/boot/video-vga.c                  |   12 -
 arch/x86/boot/video.c                      |  157 --------------
 arch/x86/kernel/acpi/Makefile              |    9 
 arch/x86/kernel/acpi/realmode/Makefile     |   55 +++++
 arch/x86/kernel/acpi/realmode/copy.S       |    1 
 arch/x86/kernel/acpi/realmode/video-bios.c |    1 
 arch/x86/kernel/acpi/realmode/video-mode.c |    1 
 arch/x86/kernel/acpi/realmode/video-vesa.c |    1 
 arch/x86/kernel/acpi/realmode/video-vga.c  |    1 
 arch/x86/kernel/acpi/realmode/wakemain.c   |   26 ++
 arch/x86/kernel/acpi/realmode/wakeup.S     |  122 +++++++++++
 arch/x86/kernel/acpi/realmode/wakeup.h     |   29 ++
 arch/x86/kernel/acpi/realmode/wakeup.ld    |   51 ++++
 arch/x86/kernel/acpi/sleep.c               |   80 ++++++-
 arch/x86/kernel/acpi/wakeup_32.S           |  245 +---------------------
 arch/x86/kernel/acpi/wakeup_64.S           |  313 -----------------------------
 arch/x86/kernel/acpi/wakeup_rm.S           |   10 
 arch/x86/kernel/head_64.S                  |    4 
 arch/x86/kernel/setup_32.c                 |    4 
 arch/x86/kernel/smpboot_64.c               |   10 
 25 files changed, 614 insertions(+), 712 deletions(-)

Index: linux-2.6/arch/x86/boot/Makefile
===================================================================
--- linux-2.6.orig/arch/x86/boot/Makefile
+++ linux-2.6/arch/x86/boot/Makefile
@@ -30,7 +30,7 @@ subdir-		:= compressed
 
 setup-y		+= a20.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
+setup-y		+= printf.o string.o tty.o video.o video-mode.o version.o
 setup-$(CONFIG_X86_APM_BOOT) += apm.o
 setup-$(CONFIG_X86_VOYAGER) += voyager.o
 
Index: linux-2.6/arch/x86/boot/boot.h
===================================================================
--- linux-2.6.orig/arch/x86/boot/boot.h
+++ linux-2.6/arch/x86/boot/boot.h
@@ -286,6 +286,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);
 
Index: linux-2.6/arch/x86/boot/video-bios.c
===================================================================
--- linux-2.6.orig/arch/x86/boot/video-bios.c
+++ linux-2.6/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;
Index: linux-2.6/arch/x86/boot/video-mode.c
===================================================================
--- /dev/null
+++ linux-2.6/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;
+}
Index: linux-2.6/arch/x86/boot/video-vesa.c
===================================================================
--- linux-2.6.orig/arch/x86/boot/video-vesa.c
+++ linux-2.6/arch/x86/boot/video-vesa.c
@@ -24,7 +24,11 @@ static struct vesa_mode_info vminfo;
 
 __videocard video_vesa;
 
+#ifndef _WAKEUP
 static void vesa_store_mode_params_graphics(void);
+#else /* _WAKEUP */
+static inline void vesa_store_mode_params_graphics(void) {}
+#endif /* _WAKEUP */
 
 static int vesa_probe(void)
 {
@@ -167,6 +171,8 @@ static int vesa_set_mode(struct mode_inf
 }
 
 
+#ifndef _WAKEUP
+
 /* Switch DAC to 8-bit mode */
 static void vesa_dac_set_8bits(void)
 {
@@ -290,6 +296,8 @@ void vesa_store_edid(void)
 #endif /* CONFIG_FIRMWARE_EDID */
 }
 
+#endif /* not _WAKEUP */
+
 __videocard video_vesa =
 {
 	.card_name	= "VESA",
Index: linux-2.6/arch/x86/boot/video-vga.c
===================================================================
--- linux-2.6.orig/arch/x86/boot/video-vga.c
+++ linux-2.6/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;
 		}
Index: linux-2.6/arch/x86/boot/video.c
===================================================================
--- linux-2.6.orig/arch/x86/boot/video.c
+++ linux-2.6/arch/x86/boot/video.c
@@ -18,21 +18,6 @@
 #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];
@@ -486,6 +330,7 @@ void set_video(void)
 		printf("Undefined video mode number: %x\n", mode);
 		mode = ASK_VGA;
 	}
+	boot_params.hdr.vid_mode = mode;
 	vesa_store_edid();
 	store_mode_params();
 
Index: linux-2.6/arch/x86/kernel/acpi/Makefile
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/Makefile
+++ linux-2.6/arch/x86/kernel/acpi/Makefile
@@ -1,7 +1,14 @@
+subdir-				:= realmode
+
 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)/realmode/wakeup.bin
+
+$(obj)/realmode/wakeup.bin: FORCE
+	$(Q)$(MAKE) $(build)=$(obj)/realmode $@
+
Index: linux-2.6/arch/x86/kernel/acpi/realmode/Makefile
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/Makefile
@@ -0,0 +1,55 @@
+#
+# arch/x86/kernel/acpi/realmode/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)
Index: linux-2.6/arch/x86/kernel/acpi/realmode/copy.S
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/copy.S
@@ -0,0 +1 @@
+#include "../../../boot/copy.S"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/video-bios.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/video-bios.c
@@ -0,0 +1 @@
+#include "../../../boot/video-bios.c"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/video-mode.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/video-mode.c
@@ -0,0 +1 @@
+#include "../../../boot/video-mode.c"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/video-vesa.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/video-vesa.c
@@ -0,0 +1 @@
+#include "../../../boot/video-vesa.c"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/video-vga.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/video-vga.c
@@ -0,0 +1 @@
+#include "../../../boot/video-vga.c"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakemain.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/wakemain.c
@@ -0,0 +1,26 @@
+#include "wakeup.h"
+#include "boot.h"
+
+extern volatile struct wakeup_header wakeup_header;
+
+void main(void)
+{
+	/* Kill machine if structures are wrong */
+	if (wakeup_header.real_magic != 0x12345678)
+		while(1);
+
+	if (wakeup_header.realmode_flags & 4) {
+		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");
+	}
+
+	if (wakeup_header.realmode_flags & 1) {
+		asm volatile("lcallw   $0xc000,$3");
+//		("movw    %cs, %ax;	movw    %ax, %ds;	movw	%ax, %es; movw    %ax, %ss");
+	}
+
+	if (wakeup_header.realmode_flags & 2) {
+		/* Need to call BIOS */
+		probe_cards(0);
+		set_mode(wakeup_header.video_mode);
+	}
+}
Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
@@ -0,0 +1,122 @@
+/*
+ * ACPI wakeup real mode startup stub
+ */
+#include <asm/segment.h>
+#include <asm/msr-index.h>
+#include <asm/page_64.h>
+#include <asm/pgtable_64.h>
+
+	.code16
+	.section ".header", "a"
+
+/* This should match the structure in wakeup.h */
+		.globl	wakeup_header
+wakeup_header:
+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
+realmode_flags:	.long	0
+real_magic:	.long	0
+trampoline_segment:	.word 0
+signature:	.long	0x51ee1111
+
+	.text
+	.globl	_start
+	.code16
+wakeup_code:
+_start:
+	cli
+	cld
+
+	/* Set up segments */
+	movw	%cs, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %ss
+
+	movl	$wakeup_stack_end, %esp
+
+	/* 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... */
+
+#ifndef CONFIG_64BIT
+	/* 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
+#else
+	pushw	$0
+	pushw	trampoline_segment
+	pushw	$0
+	lret
+#endif
+
+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:
Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.h
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/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 video_mode;		/* Video mode number */
+	u16 _jmp1;		/* ljmpl opcode, 32-bit only */
+	u32 pmode_entry;	/* Protected mode resume point, 32-bit only */
+	u16 _jmp2;		/* CS value, 32-bit only */
+	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 realmode_flags;
+	u32 real_magic;
+	u16 trampoline_segment;	/* segment with trampoline code, 64-bit only */
+	u32 signature;		/* To check we have correct structure */
+} __attribute__((__packed__));
+
+#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.ld
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.ld
@@ -0,0 +1,51 @@
+/*
+ * 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!");
+}
Index: linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c
+++ linux-2.6/arch/x86/kernel/acpi/sleep.c
@@ -11,29 +11,84 @@
 #include <linux/cpumask.h>
 
 #include <asm/smp.h>
+#include "realmode/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 acpi_copy_wakeup_routine(unsigned long);
+extern unsigned long setup_trampoline(void);
+extern void wakeup_long64(void);
+
+extern unsigned long saved_video_mode;
+extern long saved_magic;
+extern volatile unsigned long init_rsp;
+extern void (*initial_code)(void);
+#ifndef CONFIG_64BIT
+extern int wakeup_pmode_return;
+extern char swsusp_pg_dir[PAGE_SIZE];
+#else
+static char temp_stack[10240];
+#endif
+
+extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
 
 /**
  * acpi_save_state_mem - save kernel state
  *
  * 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(KERN_ERR "Could not allocate memory during boot, S3 disabled\n");
+	struct wakeup_header *header;
+
+	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);
+
+	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
+	if (header->signature != 0x51ee1111) {
+		printk(KERN_ERR "wakeup header does not match\n");
+		return -EINVAL;
+	}
+
+	header->video_mode = saved_video_mode;
+
+#ifndef CONFIG_64BIT
+	store_gdt(&header->pmode_gdt);
+
+	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);
+	}
+#endif /* !CONFIG_64BIT */
+
+	header->pmode_cr0 = read_cr0();
+	header->pmode_cr4 = read_cr4();
+	header->realmode_flags = acpi_realmode_flags;
+	header->real_magic = 0x12345678;
+
+#ifndef CONFIG_64BIT
+	header->pmode_entry = &wakeup_pmode_return;
+	header->pmode_cr3 = swsusp_pg_dir - __PAGE_OFFSET;
+	saved_magic = 0x12345678;
+#else /* CONFIG_64BIT */
+	header->trampoline_segment = setup_trampoline() >> 4;
+	init_rsp = (unsigned long)temp_stack + 4096;
+	initial_code = wakeup_long64;
+	saved_magic = 0x123456789abcdef0;
+#endif /* CONFIG_64BIT */
 
 	return 0;
 }
@@ -56,15 +111,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;
 }
 
 
Index: linux-2.6/arch/x86/kernel/acpi/wakeup_32.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/wakeup_32.S
+++ linux-2.6/arch/x86/kernel/acpi/wakeup_32.S
@@ -3,178 +3,12 @@
 #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
-
-	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:
-
-	# 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_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
+# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
 
 	.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:
 	movw	$__KERNEL_DS, %ax
 	movw	%ax, %ss
@@ -187,7 +21,7 @@ wakeup_pmode_return:
 	lgdt	saved_gdt
 	lidt	saved_idt
 	lldt	saved_ldt
-	ljmp	$(__KERNEL_CS),$1f
+	ljmp	$(__KERNEL_CS), $1f
 1:
 	movl	%cr3, %eax
 	movl	%eax, %cr3
@@ -201,82 +35,41 @@ wakeup_pmode_return:
 	jne	bogus_magic
 
 	# jump to place where we left off
-	movl	saved_eip,%eax
+	movl	saved_eip, %eax
 	jmp	*%eax
 
 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
-	movl %ebp, saved_context_ebp
-	movl %esi, saved_context_esi
-	movl %edi, saved_context_edi
-	pushfl ; popl saved_context_eflags
+	movl	%ebx, saved_context_ebx
+	movl	%ebp, saved_context_ebp
+	movl	%esi, saved_context_esi
+	movl	%edi, saved_context_edi
+	pushfl
+	popl	saved_context_eflags
 
-	movl $ret_point, saved_eip
+	movl	$ret_point, saved_eip
 	ret
 
 
 restore_registers:
-	movl saved_context_ebp, %ebp
-	movl saved_context_ebx, %ebx
-	movl saved_context_esi, %esi
-	movl saved_context_edi, %edi
-	pushl saved_context_eflags ; popfl
-	ret	
+	movl	saved_context_ebp, %ebp
+	movl	saved_context_ebx, %ebx
+	movl	saved_context_esi, %esi
+	movl	saved_context_edi, %edi
+	pushl	saved_context_eflags
+	popfl
+	ret
 
 ENTRY(do_suspend_lowlevel)
 	call	save_processor_state
Index: linux-2.6/arch/x86/kernel/acpi/wakeup_64.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/wakeup_64.S
+++ linux-2.6/arch/x86/kernel/acpi/wakeup_64.S
@@ -7,191 +7,18 @@
 #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:
-
-	mov	%ds, %ax			# Find 32bit wakeup_code addr
-	movzx   %ax, %esi			# (Convert %ds:gdt to a liner ptr)
-	shll    $4, %esi
-						# Fix up the vectors
-	addl    %esi, wakeup_32_vector - wakeup_code
-	addl    %esi, wakeup_long64_vector - wakeup_code
-	addl    %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
-
-	lidtl	%ds:idt_48a - wakeup_code
-	lgdtl	%ds:gdt_48a - wakeup_code	# load gdt with whatever is
-						# appropriate
-
-	movl	$1, %eax			# protected mode (PE) bit
-	lmsw	%ax				# This is it!
-	jmp	1f
-1:
-
-	ljmpl   *(wakeup_32_vector - wakeup_code)
-
-	.balign 4
-wakeup_32_vector:
-	.long   wakeup_32 - wakeup_code
-	.word   __KERNEL32_CS, 0
-
-	.code32
-wakeup_32:
-# Running in this code, but at low address; paging is not yet turned on.
-
-	movl	$__KERNEL_DS, %eax
-	movl	%eax, %ds
-
-	/*
-	 * Prepare for entering 64bits mode
-	 */
-
-	/* Enable PAE */
-	xorl	%eax, %eax
-	btsl	$5, %eax
-	movl	%eax, %cr4
-
-	/* Setup early boot stage 4 level pagetables */
-	leal    (wakeup_level4_pgt - wakeup_code)(%esi), %eax
-	movl	%eax, %cr3
-
-        /* Check if nx is implemented */
-        movl    $0x80000001, %eax
-        cpuid
-        movl    %edx,%edi
-
-	/* Enable Long Mode */
-	xorl    %eax, %eax
-	btsl	$_EFER_LME, %eax
-
-	/* No Execute supported? */
-	btl	$20,%edi
-	jnc     1f
-	btsl	$_EFER_NX, %eax
-				
-	/* Make changes effective */
-1:	movl    $MSR_EFER, %ecx
-	xorl    %edx, %edx
-	wrmsr
-
-	xorl	%eax, %eax
-	btsl	$31, %eax			/* Enable paging and in turn activate Long Mode */
-	btsl	$0, %eax			/* Enable protected mode */
-
-	/* Make changes effective */
-	movl	%eax, %cr0
-
-	/* At this point:
-		CR4.PAE must be 1
-		CS.L must be 0
-		CR3 must point to PML4
-		Next instruction must be a branch
-		This must be on identity-mapped page
-	*/
-	/*
-	 * At this point we're in long mode but in 32bit compatibility mode
-	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
-	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
-	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
-	 */
-
-	/* Finally jump in 64bit mode */
-        ljmp    *(wakeup_long64_vector - wakeup_code)(%esi)
-
-	.balign 4
-wakeup_long64_vector:
-	.long   wakeup_long64 - wakeup_code
-	.word   __KERNEL_CS, 0
 
 .code64
-
-	/* Hooray, we are in Long 64-bit mode (but still running in
-	 * low memory)
-	 */
-wakeup_long64:
 	/*
-	 * We must switch to a new descriptor in kernel space for the GDT
-	 * because soon the kernel won't have access anymore to the userspace
-	 * addresses where we're currently running on. We have to do that here
-	 * because in 32bit we couldn't load a 64bit linear address.
+	 * Hooray, we are in Long 64-bit mode (but still running in low memory)
 	 */
-	lgdt	cpu_gdt_descr
-
-	movq    saved_magic, %rax
-	movq    $0x123456789abcdef0, %rdx
-	cmpq    %rdx, %rax
-	jne     bogus_64_magic
+ENTRY(wakeup_long64)
+wakeup_long64:
+	movq	saved_magic, %rax
+	movq	$0x123456789abcdef0, %rdx
+	cmpq	%rdx, %rax
+	jne	bogus_64_magic
 
-	nop
-	nop
 	movw	$__KERNEL_DS, %ax
 	movw	%ax, %ss	
 	movw	%ax, %ds
@@ -208,130 +35,8 @@ wakeup_long64:
 	movq	saved_rip, %rax
 	jmp	*%rax
 
-.code32
-
-	.align	64	
-gdta:
-	/* Its good to keep gdt in sync with one in trampoline.S */
-	.word	0, 0, 0, 0			# dummy
-	/* ??? Why I need the accessed bit set in order for this to work? */
-	.quad   0x00cf9b000000ffff              # __KERNEL32_CS
-	.quad   0x00af9b000000ffff              # __KERNEL_CS
-	.quad   0x00cf93000000ffff              # __KERNEL_DS
-
-idt_48a:
-	.word	0				# idt limit = 0
-	.word	0, 0				# idt base = 0L
-
-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
-wakeup_stack:		# Just below end of page
-
-.org   0x1000
-ENTRY(wakeup_level4_pgt)
-	.quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
-	.fill   510,8,0
-	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
-	.quad   level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
-
-ENTRY(wakeup_end)
-	
-##
-# acpi_copy_wakeup_routine
-#
-# Copy the above routine to low memory.
-#
-# Parameters:
-# %rdi:	place to copy wakeup routine to
-#
-# Returned address is location of code in low memory (past data and stack)
-#
-	.code64
-ENTRY(acpi_copy_wakeup_routine)
-	pushq	%rax
-	pushq	%rdx
-
-	movl	saved_video_mode, %edx
-	movl	%edx, video_mode - wakeup_start (,%rdi)
-	movl	acpi_realmode_flags, %edx
-	movl	%edx, realmode_flags - wakeup_start (,%rdi)
-	movq	$0x12345678, real_magic - wakeup_start (,%rdi)
-	movq	$0x123456789abcdef0, %rdx
-	movq	%rdx, saved_magic
-
-	movq    saved_magic, %rax
-	movq    $0x123456789abcdef0, %rdx
-	cmpq    %rdx, %rax
-	jne     bogus_64_magic
-
-	# restore the regs we used
-	popq	%rdx
-	popq	%rax
-ENTRY(do_suspend_lowlevel_s4bios)
-	ret
+	jmp	bogus_64_magic
 
 	.align 2
 	.p2align 4,,15
@@ -414,7 +119,7 @@ do_suspend_lowlevel:
 	jmp	restore_processor_state
 .LFE5:
 .Lfe5:
-	.size	do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel
+	.size	do_suspend_lowlevel, .Lfe5-do_suspend_lowlevel
 	
 .data
 ALIGN
Index: linux-2.6/arch/x86/kernel/acpi/wakeup_rm.S
===================================================================
--- /dev/null
+++ linux-2.6/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/realmode/wakeup.bin"
+wakeup_code_end:
+	.size	wakeup_code_start, .-wakeup_code_start
Index: linux-2.6/arch/x86/kernel/head_64.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/head_64.S
+++ linux-2.6/arch/x86/kernel/head_64.S
@@ -127,10 +127,6 @@ ident_complete:
 	addq	%rbp, trampoline_level4_pgt + 0(%rip)
 	addq	%rbp, trampoline_level4_pgt + (511*8)(%rip)
 #endif
-#ifdef CONFIG_ACPI_SLEEP
-	addq	%rbp, wakeup_level4_pgt + 0(%rip)
-	addq	%rbp, wakeup_level4_pgt + (511*8)(%rip)
-#endif
 
 	/* Due to ENTRY(), sometimes the empty space gets filled with
 	 * zeros. Better take a jmp than relying on empty space being
Index: linux-2.6/arch/x86/kernel/setup_32.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/setup_32.c
+++ linux-2.6/arch/x86/kernel/setup_32.c
@@ -186,7 +186,7 @@ EXPORT_SYMBOL(ist_info);
 extern void early_cpu_init(void);
 extern int root_mountflags;
 
-unsigned long saved_videomode;
+unsigned long saved_video_mode;
 
 #define RAMDISK_IMAGE_START_MASK	0x07FF
 #define RAMDISK_PROMPT_FLAG		0x8000
@@ -713,7 +713,7 @@ void __init setup_arch(char **cmdline_p)
 	edid_info = boot_params.edid_info;
 	apm_info.bios = boot_params.apm_bios_info;
 	ist_info = boot_params.ist_info;
-	saved_videomode = boot_params.hdr.vid_mode;
+	saved_video_mode = boot_params.hdr.vid_mode;
 	if( boot_params.sys_desc_table.length != 0 ) {
 		set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2);
 		machine_id = boot_params.sys_desc_table.table[0];
Index: linux-2.6/arch/x86/kernel/smpboot_64.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/smpboot_64.c
+++ linux-2.6/arch/x86/kernel/smpboot_64.c
@@ -132,7 +132,7 @@ struct task_struct *idle_thread_array[NR
  * has made sure it's suitably aligned.
  */
 
-static unsigned long __cpuinit setup_trampoline(void)
+unsigned long __cpuinit setup_trampoline(void)
 {
 	void *tramp = __va(SMP_TRAMPOLINE_BASE); 
 	memcpy(tramp, trampoline_data, trampoline_end - trampoline_data);
@@ -649,6 +649,9 @@ do_rest:
 	*((volatile unsigned short *) phys_to_virt(0x467)) = start_rip & 0xf;
 	Dprintk("3.\n");
 
+	/* Trampoline assumes it is at beggining of segment */
+	BUG_ON(start_rip & 0xf);
+
 	/*
 	 * Be paranoid about clearing APIC errors.
 	 */
@@ -656,11 +659,6 @@ do_rest:
 	apic_read(APIC_ESR);
 
 	/*
-	 * Status is now clean
-	 */
-	boot_error = 0;
-
-	/*
 	 * Starting actual IPI sequence...
 	 */
 	boot_error = wakeup_secondary_via_INIT(apicid, start_rip);

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:12     ` Rafael J. Wysocki
@ 2008-02-07 22:28       ` Sam Ravnborg
  2008-02-07 22:34         ` H. Peter Anvin
                           ` (4 more replies)
  2008-02-07 22:28       ` Pavel Machek
  2008-02-07 22:38       ` H. Peter Anvin
  2 siblings, 5 replies; 62+ messages in thread
From: Sam Ravnborg @ 2008-02-07 22:28 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Pavel Machek, kernel list, Linux-pm mailing list, H. Peter Anvin

> ===================================================================
> --- /dev/null
> +++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.ld
> @@ -0,0 +1,51 @@
> +/*
> + * 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) }

Can we please use C style in this file.
Like this:

{
	.header : {
		*(.header)
	}

It is not as short as the above but it pays of to keep
an consistent style in the whole file and across
different .lds files.

And for good measure name it wakeup.lds.

Do we never need data from a .h file?
If we do name it wakeup.lds.S and kbuild
will fix it (assuming we have wakeup.lds
as a prerequisite where it is needed.

> +
> +	. = 0;
> +	.text		: { *(.text*) }
> +
> +	. = ALIGN(16);
Why?
> +	.rodata		: { *(.rodata*) }
> +
> +	.videocards	: {
> +		video_cards = .;
> +		*(.videocards)
> +		video_cards_end = .;
> +	}
> +
> +	. = ALIGN(16);
Why?
> +	.data		: { *(.data*) }
> +
> +	.signature	: {
> +		end_signature = .;
> +		LONG(0x65a22c82)
> +	}
> +
> +	. = ALIGN(16);
Why?
> +	.bss		:
> +	{
> +		__bss_start = .;
> +		*(.bss)
> +		__bss_end = .;
> +	}
> +
> +	. = ALIGN(16);
Why?
> +	_end = .;
> +
> +	/DISCARD/ : { *(.note*) }
> +
> +	/* Adjust this as appropriate */
> +	/* This allows 4 pages (16K) */
> +	. = ASSERT(_end <= 0x4000, "Wakeup too big!");
PAGE_SIZE * 4?


	Sam

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:12     ` Rafael J. Wysocki
  2008-02-07 22:28       ` Sam Ravnborg
@ 2008-02-07 22:28       ` Pavel Machek
  2008-02-07 22:40         ` Rafael J. Wysocki
  2008-02-07 22:46         ` H. Peter Anvin
  2008-02-07 22:38       ` H. Peter Anvin
  2 siblings, 2 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-07 22:28 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: kernel list, Linux-pm mailing list, H. Peter Anvin

Hi!

> > > > This rewrites wakeup code to .c, and it fixes stack (should use movl
> > > > ,%esp, not movw). Testers wanted. Makefile infrastructure was done by
> > > > hpa, cleanups by rjw.
> > > 
> > > I'll test it tomorrow
> > 
> > Works on my nx6325 (good sign, the box is easy to break ;-)).
> > 
> > > and I still have some more cleanups (I was distracted by a nasty scheduler
> > > issue in the current mainline).
> > 
> > The cleanups are still in the works (sorry).
> 
> Below is a version with some easy cleanups, rebased on top of the patches that
> move the 64-bit hibernation code to arch/x86/power .

Can you post a delta against my versoin? I do not see any changes from
a quick glance.

This is probably more acceptable version of beep; but there are
probably even better ways to clean it...

        if (wakeup_header.realmode_flags & 4) {
                inb(97);
                outb(0, 0x80);
                outb(3, 97);
                outb(0, 0x80);
                outb(-74, 67);
                outb(0, 0x80);
                outb(-119, 66);
                outb(0, 0x80);
                outb(15, 66);
        }

...like the version that makes beep/pause/beep/pause, so that user can
count them.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:28       ` Sam Ravnborg
@ 2008-02-07 22:34         ` H. Peter Anvin
  2008-02-08 21:31         ` Pavel Machek
                           ` (3 subsequent siblings)
  4 siblings, 0 replies; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-07 22:34 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Rafael J. Wysocki, Pavel Machek, kernel list, Linux-pm mailing list

Sam Ravnborg wrote:
>> +
>> +	. = 0;
>> +	.text		: { *(.text*) }
>> +
>> +	. = ALIGN(16);
> Why?

It's good practice to have at least paragraph (segment boundary) 
alignment between different types of data.  In the case of the .bss, it 
also allows cleaning with rep;movsl.

It's technically not all that necessary (except for 4-byte alignment for 
the .bss), but it makes things easier to debug on the assembly level.

>> +	/* Adjust this as appropriate */
>> +	/* This allows 4 pages (16K) */
>> +	. = ASSERT(_end <= 0x4000, "Wakeup too big!");
> PAGE_SIZE * 4?

Not really, because it's not at all related to the kernel page size; the 
reference to pages there is informal.  If we go to a larger virtual page 
size we do NOT want this to change.

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:12     ` Rafael J. Wysocki
  2008-02-07 22:28       ` Sam Ravnborg
  2008-02-07 22:28       ` Pavel Machek
@ 2008-02-07 22:38       ` H. Peter Anvin
  2008-02-07 23:06         ` Rafael J. Wysocki
                           ` (2 more replies)
  2 siblings, 3 replies; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-07 22:38 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

Rafael J. Wysocki wrote:
> Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
> ===================================================================
> --- /dev/null
> +++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
> @@ -0,0 +1,122 @@
> +/*
> + * ACPI wakeup real mode startup stub
> + */
> +#include <asm/segment.h>
> +#include <asm/msr-index.h>
> +#include <asm/page_64.h>
> +#include <asm/pgtable_64.h>
> +
> +	.code16
> +	.section ".header", "a"
> +
> +/* This should match the structure in wakeup.h */
> +		.globl	wakeup_header
> +wakeup_header:
> +video_mode:	.short	0	/* Video mode number */
> +pmode_return:	.byte	0x66, 0xea	/* ljmpl */
> +		.long	0	/* offset goes here */
> +		.short	__KERNEL_CS

Missing a .short pad here... Pavel fixed that at some point, I thought.

> +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
> +realmode_flags:	.long	0
> +real_magic:	.long	0
> +trampoline_segment:	.word 0
> +signature:	.long	0x51ee1111
> +
> +	.text
> +	.globl	_start
> +	.code16
> +wakeup_code:
> +_start:
> +	cli
> +	cld
> +
> +	/* Set up segments */
> +	movw	%cs, %ax
> +	movw	%ax, %ds
> +	movw	%ax, %es
> +	movw	%ax, %ss
> +
> +	movl	$wakeup_stack_end, %esp
> +
> +	/* 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... */
> +
> +#ifndef CONFIG_64BIT
> +	/* 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
> +#else
> +	pushw	$0
> +	pushw	trampoline_segment
> +	pushw	$0
> +	lret
> +#endif
> +
> +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:
> Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.h
> ===================================================================
> --- /dev/null
> +++ linux-2.6/arch/x86/kernel/acpi/realmode/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 video_mode;		/* Video mode number */
> +	u16 _jmp1;		/* ljmpl opcode, 32-bit only */
> +	u32 pmode_entry;	/* Protected mode resume point, 32-bit only */
> +	u16 _jmp2;		/* CS value, 32-bit only */
> +	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 realmode_flags;
> +	u32 real_magic;
> +	u16 trampoline_segment;	/* segment with trampoline code, 64-bit only */
> +	u32 signature;		/* To check we have correct structure */
> +} __attribute__((__packed__));
> +
> +#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
> Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.ld
> ===================================================================
> --- /dev/null
> +++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.ld
> @@ -0,0 +1,51 @@
> +/*
> + * 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!");
> +}
> Index: linux-2.6/arch/x86/kernel/acpi/sleep.c
> ===================================================================
> --- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c
> +++ linux-2.6/arch/x86/kernel/acpi/sleep.c
> @@ -11,29 +11,84 @@
>  #include <linux/cpumask.h>
>  
>  #include <asm/smp.h>
> +#include "realmode/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 acpi_copy_wakeup_routine(unsigned long);
> +extern unsigned long setup_trampoline(void);
> +extern void wakeup_long64(void);
> +
> +extern unsigned long saved_video_mode;
> +extern long saved_magic;
> +extern volatile unsigned long init_rsp;
> +extern void (*initial_code)(void);
> +#ifndef CONFIG_64BIT
> +extern int wakeup_pmode_return;
> +extern char swsusp_pg_dir[PAGE_SIZE];
> +#else
> +static char temp_stack[10240];
> +#endif
> +
> +extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
>  
>  /**
>   * acpi_save_state_mem - save kernel state
>   *
>   * 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(KERN_ERR "Could not allocate memory during boot, S3 disabled\n");
> +	struct wakeup_header *header;
> +
> +	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);

Using a PAGE_SIZE multiplier here isn't a good thing...

> +	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);

... especially not with magic constants like this.

If you're putting the "header" at the end, then you should also replace 
the end_signature stuff since that's, then, redundant.  Furthermore, by 
doing so, you're also padding the binary out to its maximum length, so 
you might as well just remove the .bss-clearing stuff.

It's not really clear to me why to do this what way...

> +	if (header->signature != 0x51ee1111) {
> +		printk(KERN_ERR "wakeup header does not match\n");
> +		return -EINVAL;
> +	}
> +
> +	header->video_mode = saved_video_mode;
> +
> +#ifndef CONFIG_64BIT
> +	store_gdt(&header->pmode_gdt);
> +
> +	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);
> +	}

Yes, why not save EFER every time?

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:28       ` Pavel Machek
@ 2008-02-07 22:40         ` Rafael J. Wysocki
  2008-02-07 22:44           ` H. Peter Anvin
                             ` (2 more replies)
  2008-02-07 22:46         ` H. Peter Anvin
  1 sibling, 3 replies; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-07 22:40 UTC (permalink / raw)
  To: Pavel Machek; +Cc: kernel list, Linux-pm mailing list, H. Peter Anvin

On Thursday, 7 of February 2008, Pavel Machek wrote:
> Hi!
> 
> > > > > This rewrites wakeup code to .c, and it fixes stack (should use movl
> > > > > ,%esp, not movw). Testers wanted. Makefile infrastructure was done by
> > > > > hpa, cleanups by rjw.
> > > > 
> > > > I'll test it tomorrow
> > > 
> > > Works on my nx6325 (good sign, the box is easy to break ;-)).
> > > 
> > > > and I still have some more cleanups (I was distracted by a nasty scheduler
> > > > issue in the current mainline).
> > > 
> > > The cleanups are still in the works (sorry).
> > 
> > Below is a version with some easy cleanups, rebased on top of the patches that
> > move the 64-bit hibernation code to arch/x86/power .
> 
> Can you post a delta against my versoin? I do not see any changes from
> a quick glance.

Appended (plus I removed two hunks, one in arch/x86/Makefile and one in
drivers/acpi/sleep/main.c that were unrelated to the rest of the patch).
 
> This is probably more acceptable version of beep; but there are
> probably even better ways to clean it...
> 
>         if (wakeup_header.realmode_flags & 4) {
>                 inb(97);
>                 outb(0, 0x80);
>                 outb(3, 97);
>                 outb(0, 0x80);
>                 outb(-74, 67);
>                 outb(0, 0x80);
>                 outb(-119, 66);
>                 outb(0, 0x80);
>                 outb(15, 66);
>         }
> 
> ...like the version that makes beep/pause/beep/pause, so that user can
> count them.

Can we move it into a separate function?

Rafael

---
 arch/x86/boot/video-vesa.c             |   12 
 arch/x86/kernel/acpi/Makefile          |    2 
 arch/x86/kernel/acpi/realmode/Makefile |    2 
 arch/x86/kernel/acpi/realmode/wakeup.S |   34 +-
 arch/x86/kernel/acpi/wakeup.S          |    1 
 arch/x86/kernel/acpi/wakeup_32.S       |   34 +-
 arch/x86/kernel/acpi/wakeup_64.S       |   21 -
 arch/x86/kernel/acpi/wakeup_rm.S       |    2 
 arch/x86_64/kernel/acpi/wakeup.S       |  425 ---------------------------------
 9 files changed, 50 insertions(+), 483 deletions(-)

Index: linux-2.6/arch/x86_64/kernel/acpi/wakeup.S
===================================================================
--- linux-2.6.orig/arch/x86_64/kernel/acpi/wakeup.S
+++ /dev/null
@@ -1,425 +0,0 @@
-.text
-#include <linux/linkage.h>
-#include <asm/segment.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/msr.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:
-
-	mov	%ds, %ax			# Find 32bit wakeup_code addr
-	movzx   %ax, %esi			# (Convert %ds:gdt to a liner ptr)
-	shll    $4, %esi
-						# Fix up the vectors
-	addl    %esi, wakeup_32_vector - wakeup_code
-	addl    %esi, wakeup_long64_vector - wakeup_code
-	addl    %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
-
-	lidtl	%ds:idt_48a - wakeup_code
-	lgdtl	%ds:gdt_48a - wakeup_code	# load gdt with whatever is
-						# appropriate
-
-	movl	$1, %eax			# protected mode (PE) bit
-	lmsw	%ax				# This is it!
-	jmp	1f
-1:
-
-	ljmpl   *(wakeup_32_vector - wakeup_code)
-
-	.balign 4
-wakeup_32_vector:
-	.long   wakeup_32 - wakeup_code
-	.word   __KERNEL32_CS, 0
-
-	.code32
-wakeup_32:
-# Running in this code, but at low address; paging is not yet turned on.
-
-	movl	$__KERNEL_DS, %eax
-	movl	%eax, %ds
-
-	/*
-	 * Prepare for entering 64bits mode
-	 */
-
-	/* Enable PAE */
-	xorl	%eax, %eax
-	btsl	$5, %eax
-	movl	%eax, %cr4
-
-	/* Setup early boot stage 4 level pagetables */
-	leal    (wakeup_level4_pgt - wakeup_code)(%esi), %eax
-	movl	%eax, %cr3
-
-        /* Check if nx is implemented */
-        movl    $0x80000001, %eax
-        cpuid
-        movl    %edx,%edi
-
-	/* Enable Long Mode */
-	xorl    %eax, %eax
-	btsl	$_EFER_LME, %eax
-
-	/* No Execute supported? */
-	btl	$20,%edi
-	jnc     1f
-	btsl	$_EFER_NX, %eax
-				
-	/* Make changes effective */
-1:	movl    $MSR_EFER, %ecx
-	xorl    %edx, %edx
-	wrmsr
-
-	xorl	%eax, %eax
-	btsl	$31, %eax			/* Enable paging and in turn activate Long Mode */
-	btsl	$0, %eax			/* Enable protected mode */
-
-	/* Make changes effective */
-	movl	%eax, %cr0
-
-	/* At this point:
-		CR4.PAE must be 1
-		CS.L must be 0
-		CR3 must point to PML4
-		Next instruction must be a branch
-		This must be on identity-mapped page
-	*/
-	/*
-	 * At this point we're in long mode but in 32bit compatibility mode
-	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
-	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
-	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
-	 */
-
-	/* Finally jump in 64bit mode */
-        ljmp    *(wakeup_long64_vector - wakeup_code)(%esi)
-
-	.balign 4
-wakeup_long64_vector:
-	.long   wakeup_long64 - wakeup_code
-	.word   __KERNEL_CS, 0
-
-.code64
-
-	/* Hooray, we are in Long 64-bit mode (but still running in
-	 * low memory)
-	 */
-wakeup_long64:
-	/*
-	 * We must switch to a new descriptor in kernel space for the GDT
-	 * because soon the kernel won't have access anymore to the userspace
-	 * addresses where we're currently running on. We have to do that here
-	 * because in 32bit we couldn't load a 64bit linear address.
-	 */
-	lgdt	cpu_gdt_descr
-
-	movq    saved_magic, %rax
-	movq    $0x123456789abcdef0, %rdx
-	cmpq    %rdx, %rax
-	jne     bogus_64_magic
-
-	nop
-	nop
-	movw	$__KERNEL_DS, %ax
-	movw	%ax, %ss	
-	movw	%ax, %ds
-	movw	%ax, %es
-	movw	%ax, %fs
-	movw	%ax, %gs
-	movq	saved_rsp, %rsp
-
-	movq	saved_rbx, %rbx
-	movq	saved_rdi, %rdi
-	movq	saved_rsi, %rsi
-	movq	saved_rbp, %rbp
-
-	movq	saved_rip, %rax
-	jmp	*%rax
-
-.code32
-
-	.align	64	
-gdta:
-	/* Its good to keep gdt in sync with one in trampoline.S */
-	.word	0, 0, 0, 0			# dummy
-	/* ??? Why I need the accessed bit set in order for this to work? */
-	.quad   0x00cf9b000000ffff              # __KERNEL32_CS
-	.quad   0x00af9b000000ffff              # __KERNEL_CS
-	.quad   0x00cf93000000ffff              # __KERNEL_DS
-
-idt_48a:
-	.word	0				# idt limit = 0
-	.word	0, 0				# idt base = 0L
-
-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
-wakeup_stack:		# Just below end of page
-
-.org   0x1000
-ENTRY(wakeup_level4_pgt)
-	.quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
-	.fill   510,8,0
-	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
-	.quad   level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
-
-ENTRY(wakeup_end)
-	
-##
-# acpi_copy_wakeup_routine
-#
-# Copy the above routine to low memory.
-#
-# Parameters:
-# %rdi:	place to copy wakeup routine to
-#
-# Returned address is location of code in low memory (past data and stack)
-#
-	.code64
-ENTRY(acpi_copy_wakeup_routine)
-	pushq	%rax
-	pushq	%rdx
-
-	movl	saved_video_mode, %edx
-	movl	%edx, video_mode - wakeup_start (,%rdi)
-	movl	acpi_realmode_flags, %edx
-	movl	%edx, realmode_flags - wakeup_start (,%rdi)
-	movq	$0x12345678, real_magic - wakeup_start (,%rdi)
-	movq	$0x123456789abcdef0, %rdx
-	movq	%rdx, saved_magic
-
-	movq    saved_magic, %rax
-	movq    $0x123456789abcdef0, %rdx
-	cmpq    %rdx, %rax
-	jne     bogus_64_magic
-
-	# restore the regs we used
-	popq	%rdx
-	popq	%rax
-ENTRY(do_suspend_lowlevel_s4bios)
-	ret
-
-	.align 2
-	.p2align 4,,15
-.globl do_suspend_lowlevel
-	.type	do_suspend_lowlevel,@function
-do_suspend_lowlevel:
-.LFB5:
-	subq	$8, %rsp
-	xorl	%eax, %eax
-	call	save_processor_state
-
-	movq %rsp, saved_context_esp(%rip)
-	movq %rax, saved_context_eax(%rip)
-	movq %rbx, saved_context_ebx(%rip)
-	movq %rcx, saved_context_ecx(%rip)
-	movq %rdx, saved_context_edx(%rip)
-	movq %rbp, saved_context_ebp(%rip)
-	movq %rsi, saved_context_esi(%rip)
-	movq %rdi, saved_context_edi(%rip)
-	movq %r8,  saved_context_r08(%rip)
-	movq %r9,  saved_context_r09(%rip)
-	movq %r10, saved_context_r10(%rip)
-	movq %r11, saved_context_r11(%rip)
-	movq %r12, saved_context_r12(%rip)
-	movq %r13, saved_context_r13(%rip)
-	movq %r14, saved_context_r14(%rip)
-	movq %r15, saved_context_r15(%rip)
-	pushfq ; popq saved_context_eflags(%rip)
-
-	movq	$.L97, saved_rip(%rip)
-
-	movq %rsp,saved_rsp
-	movq %rbp,saved_rbp
-	movq %rbx,saved_rbx
-	movq %rdi,saved_rdi
-	movq %rsi,saved_rsi
-
-	addq	$8, %rsp
-	movl	$3, %edi
-	xorl	%eax, %eax
-	jmp	acpi_enter_sleep_state
-.L97:
-	.p2align 4,,7
-.L99:
-	.align 4
-	movl	$24, %eax
-	movw %ax, %ds
-	movq	saved_context+58(%rip), %rax
-	movq %rax, %cr4
-	movq	saved_context+50(%rip), %rax
-	movq %rax, %cr3
-	movq	saved_context+42(%rip), %rax
-	movq %rax, %cr2
-	movq	saved_context+34(%rip), %rax
-	movq %rax, %cr0
-	pushq saved_context_eflags(%rip) ; popfq
-	movq saved_context_esp(%rip), %rsp
-	movq saved_context_ebp(%rip), %rbp
-	movq saved_context_eax(%rip), %rax
-	movq saved_context_ebx(%rip), %rbx
-	movq saved_context_ecx(%rip), %rcx
-	movq saved_context_edx(%rip), %rdx
-	movq saved_context_esi(%rip), %rsi
-	movq saved_context_edi(%rip), %rdi
-	movq saved_context_r08(%rip), %r8
-	movq saved_context_r09(%rip), %r9
-	movq saved_context_r10(%rip), %r10
-	movq saved_context_r11(%rip), %r11
-	movq saved_context_r12(%rip), %r12
-	movq saved_context_r13(%rip), %r13
-	movq saved_context_r14(%rip), %r14
-	movq saved_context_r15(%rip), %r15
-
-	xorl	%eax, %eax
-	addq	$8, %rsp
-	jmp	restore_processor_state
-.LFE5:
-.Lfe5:
-	.size	do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel
-	
-.data
-ALIGN
-ENTRY(saved_rbp)	.quad	0
-ENTRY(saved_rsi)	.quad	0
-ENTRY(saved_rdi)	.quad	0
-ENTRY(saved_rbx)	.quad	0
-
-ENTRY(saved_rip)	.quad	0
-ENTRY(saved_rsp)	.quad	0
-
-ENTRY(saved_magic)	.quad	0
Index: linux-2.6/arch/x86/kernel/acpi/Makefile
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/Makefile
+++ linux-2.6/arch/x86/kernel/acpi/Makefile
@@ -8,7 +8,7 @@ obj-y				+= cstate.o processor.o
 endif
 
 $(obj)/wakeup_rm.o:    $(obj)/realmode/wakeup.bin
-       
+
 $(obj)/realmode/wakeup.bin: FORCE
 	$(Q)$(MAKE) $(build)=$(obj)/realmode $@
 
Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/realmode/wakeup.S
+++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
@@ -12,16 +12,14 @@
 /* This should match the structure in wakeup.h */
 		.globl	wakeup_header
 wakeup_header:
-entry:		.short	_start	/* unused */
-total:		.short	_end	/* unused */
 video_mode:	.short	0	/* Video mode number */
 pmode_return:	.byte	0x66, 0xea	/* ljmpl */
-		.long	0		/* offset goes here */
+		.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_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
 realmode_flags:	.long	0
 real_magic:	.long	0
@@ -37,10 +35,10 @@ _start:
 	cld
 
 	/* Set up segments */
-	movw	%cs,%ax
-	movw	%ax,%ds
-	movw	%ax,%es
-	movw	%ax,%ss
+	movw	%cs, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %ss
 
 	movl	$wakeup_stack_end, %esp
 
@@ -61,16 +59,17 @@ _start:
 	/* Zero the bss */
 	xorl	%eax, %eax
 	movw	$__bss_start, %di
-	movw	$__bss_end+3, %cx
+	movw	$__bss_end + 3, %cx
 	subw	%di, %cx
 	shrw	$2, %cx
-	rep; stosl
+	rep
+	stosl
 
 	/* Call the C code */
 	calll	main
 
 	/* Do any other stuff... */
-	
+
 #ifndef CONFIG_64BIT
 	/* This could also be done in C code... */
 	movl	pmode_cr3, %eax
@@ -81,7 +80,7 @@ _start:
 	movl	%ecx, %cr4
 1:
 	movl	pmode_efer, %eax
-	movl	pmode_efer+4, %edx
+	movl	pmode_efer + 4, %edx
 	movl	%eax, %ecx
 	orl	%edx, %ecx
 	jz	1f
@@ -99,14 +98,14 @@ _start:
 	pushw	$0
 	pushw	trampoline_segment
 	pushw	$0
-	lret	
+	lret
 #endif
 
 bogus_real_magic:
 1:
 	hlt
 	jmp	1b
-	
+
 	.data
 	.balign	4
 	.globl	HEAP, heap_end
@@ -121,4 +120,3 @@ wakeup_heap:
 wakeup_stack:
 	.space	2048
 wakeup_stack_end:
-
Index: linux-2.6/arch/x86/kernel/acpi/wakeup_32.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/wakeup_32.S
+++ linux-2.6/arch/x86/kernel/acpi/wakeup_32.S
@@ -5,8 +5,6 @@
 
 # Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
 
-#include "wakeup.S"
-
 	.code32
 	ALIGN
 
@@ -23,7 +21,7 @@ wakeup_pmode_return:
 	lgdt	saved_gdt
 	lidt	saved_idt
 	lldt	saved_ldt
-	ljmp	$(__KERNEL_CS),$1f
+	ljmp	$(__KERNEL_CS), $1f
 1:
 	movl	%cr3, %eax
 	movl	%eax, %cr3
@@ -37,7 +35,7 @@ wakeup_pmode_return:
 	jne	bogus_magic
 
 	# jump to place where we left off
-	movl	saved_eip,%eax
+	movl	saved_eip, %eax
 	jmp	*%eax
 
 bogus_magic:
@@ -50,26 +48,28 @@ save_registers:
 	sidt	saved_idt
 	sldt	saved_ldt
 	str	saved_tss
-	
+
 	leal	4(%esp), %eax
 	movl	%eax, saved_context_esp
-	movl %ebx, saved_context_ebx
-	movl %ebp, saved_context_ebp
-	movl %esi, saved_context_esi
-	movl %edi, saved_context_edi
-	pushfl ; popl saved_context_eflags
+	movl	%ebx, saved_context_ebx
+	movl	%ebp, saved_context_ebp
+	movl	%esi, saved_context_esi
+	movl	%edi, saved_context_edi
+	pushfl
+	popl	saved_context_eflags
 
-	movl $ret_point, saved_eip
+	movl	$ret_point, saved_eip
 	ret
 
 
 restore_registers:
-	movl saved_context_ebp, %ebp
-	movl saved_context_ebx, %ebx
-	movl saved_context_esi, %esi
-	movl saved_context_edi, %edi
-	pushl saved_context_eflags ; popfl
-	ret	
+	movl	saved_context_ebp, %ebp
+	movl	saved_context_ebx, %ebx
+	movl	saved_context_esi, %esi
+	movl	saved_context_edi, %edi
+	pushl	saved_context_eflags
+	popfl
+	ret
 
 ENTRY(do_suspend_lowlevel)
 	call	save_processor_state
Index: linux-2.6/arch/x86/boot/video-vesa.c
===================================================================
--- linux-2.6.orig/arch/x86/boot/video-vesa.c
+++ linux-2.6/arch/x86/boot/video-vesa.c
@@ -24,7 +24,11 @@ static struct vesa_mode_info vminfo;
 
 __videocard video_vesa;
 
+#ifndef _WAKEUP
 static void vesa_store_mode_params_graphics(void);
+#else /* _WAKEUP */
+static inline void vesa_store_mode_params_graphics(void) {}
+#endif /* _WAKEUP */
 
 static int vesa_probe(void)
 {
@@ -160,15 +164,15 @@ static int vesa_set_mode(struct mode_inf
 		do_restore = 1;
 	} else {
 		/* Graphics mode */
-#ifndef _WAKEUP
 		vesa_store_mode_params_graphics();
-#endif
 	}
 
 	return 0;
 }
 
 
+#ifndef _WAKEUP
+
 /* Switch DAC to 8-bit mode */
 static void vesa_dac_set_8bits(void)
 {
@@ -189,7 +193,6 @@ 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;
@@ -199,11 +202,8 @@ 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)
 {
Index: linux-2.6/arch/x86/kernel/acpi/realmode/Makefile
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/realmode/Makefile
+++ linux-2.6/arch/x86/kernel/acpi/realmode/Makefile
@@ -1,5 +1,5 @@
 #
-# arch/x86/kernel/acpi/rm/Makefile
+# arch/x86/kernel/acpi/realmode/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
Index: linux-2.6/arch/x86/kernel/acpi/wakeup_rm.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/wakeup_rm.S
+++ linux-2.6/arch/x86/kernel/acpi/wakeup_rm.S
@@ -5,6 +5,6 @@
 	.section ".rodata","a"
 	.globl	wakeup_code_start, wakeup_code_end
 wakeup_code_start:
-	.incbin	"arch/x86/kernel/acpi/rm/wakeup.bin"
+	.incbin	"arch/x86/kernel/acpi/realmode/wakeup.bin"
 wakeup_code_end:
 	.size	wakeup_code_start, .-wakeup_code_start
Index: linux-2.6/arch/x86/kernel/acpi/wakeup.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/wakeup.S
+++ /dev/null
@@ -1 +0,0 @@
-# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
Index: linux-2.6/arch/x86/kernel/acpi/wakeup_64.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/wakeup_64.S
+++ linux-2.6/arch/x86/kernel/acpi/wakeup_64.S
@@ -8,21 +8,16 @@
 
 # Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
 
-#include "wakeup.S"
-
-# Running in this code, but at low address; paging is not yet turned on.
-
 .code64
-
-	/* Hooray, we are in Long 64-bit mode (but still running in
-	 * low memory)
+	/*
+	 * Hooray, we are in Long 64-bit mode (but still running in low memory)
 	 */
 ENTRY(wakeup_long64)
 wakeup_long64:
-	movq    saved_magic, %rax
-	movq    $0x123456789abcdef0, %rdx
-	cmpq    %rdx, %rax
-	jne     bogus_64_magic
+	movq	saved_magic, %rax
+	movq	$0x123456789abcdef0, %rdx
+	cmpq	%rdx, %rax
+	jne	bogus_64_magic
 
 	movw	$__KERNEL_DS, %ax
 	movw	%ax, %ss	
@@ -41,7 +36,7 @@ wakeup_long64:
 	jmp	*%rax
 
 bogus_64_magic:
-	jmp bogus_64_magic
+	jmp	bogus_64_magic
 
 	.align 2
 	.p2align 4,,15
@@ -124,7 +119,7 @@ do_suspend_lowlevel:
 	jmp	restore_processor_state
 .LFE5:
 .Lfe5:
-	.size	do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel
+	.size	do_suspend_lowlevel, .Lfe5-do_suspend_lowlevel
 	
 .data
 ALIGN

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:40         ` Rafael J. Wysocki
@ 2008-02-07 22:44           ` H. Peter Anvin
  2008-02-07 22:53             ` Rafael J. Wysocki
  2008-02-07 22:45           ` H. Peter Anvin
  2008-02-08 21:13           ` Pavel Machek
  2 siblings, 1 reply; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-07 22:44 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

Rafael J. Wysocki wrote:
> -	rep; stosl
> +	rep
> +	stosl

Yuck!

Please don't perpetuate the braindamage that this is two instructions. 
It's one instruction with a modifier; the fact that gas wants a 
separator is broken enough as it is.

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:40         ` Rafael J. Wysocki
  2008-02-07 22:44           ` H. Peter Anvin
@ 2008-02-07 22:45           ` H. Peter Anvin
  2008-02-07 22:49             ` Pavel Machek
  2008-02-08 21:13           ` Pavel Machek
  2 siblings, 1 reply; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-07 22:45 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

Rafael J. Wysocki wrote:

>  ENTRY(wakeup_long64)
>  wakeup_long64:
> -	movq    saved_magic, %rax
> -	movq    $0x123456789abcdef0, %rdx
> -	cmpq    %rdx, %rax
> -	jne     bogus_64_magic
> +	movq	saved_magic, %rax
> +	movq	$0x123456789abcdef0, %rdx
> +	cmpq	%rdx, %rax
> +	jne	bogus_64_magic

A random magic is probably more likely to be unique than something like 
that.

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:28       ` Pavel Machek
  2008-02-07 22:40         ` Rafael J. Wysocki
@ 2008-02-07 22:46         ` H. Peter Anvin
  2008-02-07 22:51           ` Pavel Machek
  2008-02-07 22:57           ` Rafael J. Wysocki
  1 sibling, 2 replies; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-07 22:46 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

Pavel Machek wrote:
> 
> This is probably more acceptable version of beep; but there are
> probably even better ways to clean it...
> 
>         if (wakeup_header.realmode_flags & 4) {
>                 inb(97);
>                 outb(0, 0x80);
>                 outb(3, 97);
>                 outb(0, 0x80);
>                 outb(-74, 67);
>                 outb(0, 0x80);
>                 outb(-119, 66);
>                 outb(0, 0x80);
>                 outb(15, 66);
>         }
> 

What is available at this point -- are BIOS calls still accessible; are 
interrupts running?

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:45           ` H. Peter Anvin
@ 2008-02-07 22:49             ` Pavel Machek
  0 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-07 22:49 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

On Thu 2008-02-07 14:45:35, H. Peter Anvin wrote:
> Rafael J. Wysocki wrote:
>
>>  ENTRY(wakeup_long64)
>>  wakeup_long64:
>> -	movq    saved_magic, %rax
>> -	movq    $0x123456789abcdef0, %rdx
>> -	cmpq    %rdx, %rax
>> -	jne     bogus_64_magic
>> +	movq	saved_magic, %rax
>> +	movq	$0x123456789abcdef0, %rdx
>> +	cmpq	%rdx, %rax
>> +	jne	bogus_64_magic
>
> A random magic is probably more likely to be unique than something like 
> that.

This is already "unlikely enough", I'd say. It does not look like a
pointer, and it is long enough.

									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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:46         ` H. Peter Anvin
@ 2008-02-07 22:51           ` Pavel Machek
  2008-02-07 23:09             ` Rafael J. Wysocki
  2008-02-07 22:57           ` Rafael J. Wysocki
  1 sibling, 1 reply; 62+ messages in thread
From: Pavel Machek @ 2008-02-07 22:51 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

On Thu 2008-02-07 14:46:25, H. Peter Anvin wrote:
> Pavel Machek wrote:
>>
>> This is probably more acceptable version of beep; but there are
>> probably even better ways to clean it...
>>
>>         if (wakeup_header.realmode_flags & 4) {
>>                 inb(97);
>>                 outb(0, 0x80);
>>                 outb(3, 97);
>>                 outb(0, 0x80);
>>                 outb(-74, 67);
>>                 outb(0, 0x80);
>>                 outb(-119, 66);
>>                 outb(0, 0x80);
>>                 outb(15, 66);
>>         }
>>
>
> What is available at this point -- are BIOS calls still accessible; are 
> interrupts running?

No interrupts. BIOS calls work on some machines, but I'd like this to
work when bios does not.

Actually, matthieu's code is probably better to start from:

+/* one ISA cycle @8Mhz */
+#define PAUSE outb %al, $0x80
+#define WAIT_100MS \
+       movl $800000, %eax; \
+       2: \
+       PAUSE; \
+       dec %eax; \
+       jne 2b
+
+/* What's the PIT rate */
+#define COUNT 0xf89
 #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;
+       /* enable counter 2 */ \
+       inb             $0x61, %al;     \
+       PAUSE;  \
+       orb     $3, %al; \
+       outb    %al, $0x61;     \
+       PAUSE;  \
+       /* set command for counter 2, 2 byte write */ \
+       movb    $0xB6, %al;     \
+       outb    %al, $0x43;     \
+       PAUSE;  \
+       /* select desired HZ */ \
+       movb    $(COUNT & 0xff), %al; \
+       outb    %al, $0x42;     \
+       PAUSE;  \
+       movb    $(COUNT >> 8), %al;     \
+       outb    %al, $0x42; \
+       WAIT_100MS; \
+       /* disable counter 2 */ \
+       inb             $0x61, %al;     \
+       PAUSE;  \
+       andb    $0xFC, %al; \
+       outb    %al, $0x61; \
+       WAIT_100MS
+
+#define CBEEP \
+       testl   $4, realmode_flags - wakeup_code; \
+       jz      1f; \
+       BEEP; \
+1:

...because it allows user to compute number of beeps.
							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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:44           ` H. Peter Anvin
@ 2008-02-07 22:53             ` Rafael J. Wysocki
  0 siblings, 0 replies; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-07 22:53 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

On Thursday, 7 of February 2008, H. Peter Anvin wrote:
> Rafael J. Wysocki wrote:
> > -	rep; stosl
> > +	rep
> > +	stosl
> 
> Yuck!
> 
> Please don't perpetuate the braindamage that this is two instructions. 
> It's one instruction with a modifier;

Sure, it is.

> the fact that gas wants a separator is broken enough as it is.

[Well, the newline is a separator too.]  I'll keep it in one line if you want
that.

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:46         ` H. Peter Anvin
  2008-02-07 22:51           ` Pavel Machek
@ 2008-02-07 22:57           ` Rafael J. Wysocki
  2008-02-07 23:14             ` H. Peter Anvin
  1 sibling, 1 reply; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-07 22:57 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

On Thursday, 7 of February 2008, H. Peter Anvin wrote:
> Pavel Machek wrote:
> > 
> > This is probably more acceptable version of beep; but there are
> > probably even better ways to clean it...
> > 
> >         if (wakeup_header.realmode_flags & 4) {
> >                 inb(97);
> >                 outb(0, 0x80);
> >                 outb(3, 97);
> >                 outb(0, 0x80);
> >                 outb(-74, 67);
> >                 outb(0, 0x80);
> >                 outb(-119, 66);
> >                 outb(0, 0x80);
> >                 outb(15, 66);
> >         }
> > 
> 
> What is available at this point -- are BIOS calls still accessible; are 
> interrupts running?

No interrupts.

We're in the real mode, so BIOS calls should be accessible.

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:38       ` H. Peter Anvin
@ 2008-02-07 23:06         ` Rafael J. Wysocki
  2008-02-07 23:13           ` H. Peter Anvin
  2008-02-07 23:35           ` Pavel Machek
  2008-02-08 21:56         ` Pavel Machek
  2008-02-08 21:58         ` Pavel Machek
  2 siblings, 2 replies; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-07 23:06 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

On Thursday, 7 of February 2008, H. Peter Anvin wrote:
> Rafael J. Wysocki wrote:
> > Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
> > ===================================================================
> > --- /dev/null
> > +++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
> > @@ -0,0 +1,122 @@
> > +/*
> > + * ACPI wakeup real mode startup stub
> > + */
> > +#include <asm/segment.h>
> > +#include <asm/msr-index.h>
> > +#include <asm/page_64.h>
> > +#include <asm/pgtable_64.h>
> > +
> > +	.code16
> > +	.section ".header", "a"
> > +
> > +/* This should match the structure in wakeup.h */
> > +		.globl	wakeup_header
> > +wakeup_header:
> > +video_mode:	.short	0	/* Video mode number */
> > +pmode_return:	.byte	0x66, 0xea	/* ljmpl */
> > +		.long	0	/* offset goes here */
> > +		.short	__KERNEL_CS
> 
> Missing a .short pad here... Pavel fixed that at some point, I thought.

Hm, the struct in wakeup.h doesn't contain it too.  Why exactly is it
necessary?

[--snip--]
> >  	}
> > -	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);
> 
> Using a PAGE_SIZE multiplier here isn't a good thing...

Yes, I'll fix that in one of the next iterations.

> 
> > +	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
> 
> ... especially not with magic constants like this.

Yeah.  Pavel, what's at 0x3f00, btw?

> If you're putting the "header" at the end, then you should also replace 
> the end_signature stuff since that's, then, redundant.

In fact, I'd prefer to remove .signature from the header and use the
end_signature only, so that I can use struct wakeup_header for addressing
the header fields in the assembly too.

> Furthermore, by doing so, you're also padding the binary out to its maximum
> length, so you might as well just remove the .bss-clearing stuff.

Do you mean placing the header at the end will fill the area between it and the
code with zeros, so the .bss clearing is not necessary?

> It's not really clear to me why to do this what way...
> 
> > +	if (header->signature != 0x51ee1111) {
> > +		printk(KERN_ERR "wakeup header does not match\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	header->video_mode = saved_video_mode;
> > +
> > +#ifndef CONFIG_64BIT
> > +	store_gdt(&header->pmode_gdt);
> > +
> > +	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);
> > +	}
> 
> Yes, why not save EFER every time?

Well, I think we can do that.

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:51           ` Pavel Machek
@ 2008-02-07 23:09             ` Rafael J. Wysocki
  0 siblings, 0 replies; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-07 23:09 UTC (permalink / raw)
  To: Pavel Machek; +Cc: H. Peter Anvin, kernel list, Linux-pm mailing list

On Thursday, 7 of February 2008, Pavel Machek wrote:
> On Thu 2008-02-07 14:46:25, H. Peter Anvin wrote:
> > Pavel Machek wrote:
> >>
> >> This is probably more acceptable version of beep; but there are
> >> probably even better ways to clean it...
> >>
> >>         if (wakeup_header.realmode_flags & 4) {
> >>                 inb(97);
> >>                 outb(0, 0x80);
> >>                 outb(3, 97);
> >>                 outb(0, 0x80);
> >>                 outb(-74, 67);
> >>                 outb(0, 0x80);
> >>                 outb(-119, 66);
> >>                 outb(0, 0x80);
> >>                 outb(15, 66);
> >>         }
> >>
> >
> > What is available at this point -- are BIOS calls still accessible; are 
> > interrupts running?
> 
> No interrupts. BIOS calls work on some machines, but I'd like this to
> work when bios does not.
> 
> Actually, matthieu's code is probably better to start from:
> 
> +/* one ISA cycle @8Mhz */
> +#define PAUSE outb %al, $0x80
> +#define WAIT_100MS \
> +       movl $800000, %eax; \
> +       2: \
> +       PAUSE; \
> +       dec %eax; \
> +       jne 2b
> +
> +/* What's the PIT rate */
> +#define COUNT 0xf89
>  #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;
> +       /* enable counter 2 */ \
> +       inb             $0x61, %al;     \
> +       PAUSE;  \
> +       orb     $3, %al; \
> +       outb    %al, $0x61;     \
> +       PAUSE;  \
> +       /* set command for counter 2, 2 byte write */ \
> +       movb    $0xB6, %al;     \
> +       outb    %al, $0x43;     \
> +       PAUSE;  \
> +       /* select desired HZ */ \
> +       movb    $(COUNT & 0xff), %al; \
> +       outb    %al, $0x42;     \
> +       PAUSE;  \
> +       movb    $(COUNT >> 8), %al;     \
> +       outb    %al, $0x42; \
> +       WAIT_100MS; \
> +       /* disable counter 2 */ \
> +       inb             $0x61, %al;     \
> +       PAUSE;  \
> +       andb    $0xFC, %al; \
> +       outb    %al, $0x61; \
> +       WAIT_100MS
> +
> +#define CBEEP \
> +       testl   $4, realmode_flags - wakeup_code; \
> +       jz      1f; \
> +       BEEP; \
> +1:
> 
> ...because it allows user to compute number of beeps.

Hm, it seems we can convert it at least partially to C.

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 23:06         ` Rafael J. Wysocki
@ 2008-02-07 23:13           ` H. Peter Anvin
  2008-02-07 23:35           ` Pavel Machek
  1 sibling, 0 replies; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-07 23:13 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

Rafael J. Wysocki wrote:
> On Thursday, 7 of February 2008, H. Peter Anvin wrote:
>> Rafael J. Wysocki wrote:
>>> Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
>>> ===================================================================
>>> --- /dev/null
>>> +++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
>>> @@ -0,0 +1,122 @@
>>> +/*
>>> + * ACPI wakeup real mode startup stub
>>> + */
>>> +#include <asm/segment.h>
>>> +#include <asm/msr-index.h>
>>> +#include <asm/page_64.h>
>>> +#include <asm/pgtable_64.h>
>>> +
>>> +	.code16
>>> +	.section ".header", "a"
>>> +
>>> +/* This should match the structure in wakeup.h */
>>> +		.globl	wakeup_header
>>> +wakeup_header:
>>> +video_mode:	.short	0	/* Video mode number */
>>> +pmode_return:	.byte	0x66, 0xea	/* ljmpl */
>>> +		.long	0	/* offset goes here */
>>> +		.short	__KERNEL_CS
>> Missing a .short pad here... Pavel fixed that at some point, I thought.
> 
> Hm, the struct in wakeup.h doesn't contain it too.  Why exactly is it
> necessary?

Err, I guess it's only necessary if _jmp2 is declared u32.  I generally 
prefer to keep fields naturally aligned even though x86 doesn't require 
it, it's a bit of paranoia on my part.

> 
> Yeah.  Pavel, what's at 0x3f00, btw?
> 

To be fair, this might have come from my early hack, I don't know for sure.

> In fact, I'd prefer to remove .signature from the header and use the
> end_signature only, so that I can use struct wakeup_header for addressing
> the header fields in the assembly too.

I *thought* that's what I had originally.  I'm a bit confused, or it 
might have been something Pavel changed.

>> Furthermore, by doing so, you're also padding the binary out to its maximum
>> length, so you might as well just remove the .bss-clearing stuff.
> 
> Do you mean placing the header at the end will fill the area between it and the
> code with zeros, so the .bss clearing is not necessary?

Yes.  It could, of course, also be cleared by a simple memset() in the 
setup code in the kernel, as opposed by the initial assembly code. 
That's probably the preferred option.

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:57           ` Rafael J. Wysocki
@ 2008-02-07 23:14             ` H. Peter Anvin
  2008-02-08 21:35               ` Pavel Machek
  0 siblings, 1 reply; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-07 23:14 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Pavel Machek, kernel list, Linux-pm mailing list

[-- Attachment #1: Type: text/plain, Size: 121 bytes --]

Okay, this uses the iodelay as the timesource... here is the total 
silliness (and totally untested, of course.)

	-hpa


[-- Attachment #2: beep.c --]
[-- Type: text/x-csrc, Size: 1153 bytes --]

static inline void io_delay(void)
{
	outb(0, 0x80);
}

static void udelay(int loops)
{
	while (loops--)
		io_delay();	/* Approximately 1 us */
}

static void beep(unsigned int hz)
{
	u8 enable;

	if (!hz) {
		enable = 0x00;		/* Turn off speaker */
	} else {
		u16 div = 1193181/hz;

		outb(0xb6, 0x43);	/* Ctr 2, squarewave, load, binary */
		io_delay();
		outb(div, 0x42);	/* LSB of counter */
		io_delay();
		outb(div >> 8, 0x42);	/* MSB of counter */
		io_delay();

		enable = 0x03;		/* Turn on speaker */
	}
	inb(0x61);		/* Dummy read of System Control Port B */
	io_delay();
	outb(enable, 0x61);	/* Enable timer 2 output to speaker */
	io_delay();
}

#define DOT_HZ		880
#define DASH_HZ		587
#define US_PER_DOT	125000

/* Okay, this is totally silly, but it's kind of fun. */
void send_morse(const char *pattern)
{
	char s;

	while ((s = *pattern++)) {
		switch (s) {
		case '.':
			beep(DOT_HZ);
			udelay(US_PER_DOT);
			beep(0);
			udelay(US_PER_DOT);
			break;
		case '-':
			beep(DASH_HZ);
			udelay(US_PER_DOT*3);
			beep(0);
			udelay(US_PER_DOT);
			break;
		default:	/* Assume it's a space */
			udelay(US_PER_DOT*3);
			break;
		}
	}
}



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 23:06         ` Rafael J. Wysocki
  2008-02-07 23:13           ` H. Peter Anvin
@ 2008-02-07 23:35           ` Pavel Machek
  2008-02-07 23:36             ` Rafael J. Wysocki
  2008-02-07 23:42             ` H. Peter Anvin
  1 sibling, 2 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-07 23:35 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: H. Peter Anvin, kernel list, Linux-pm mailing list

Hi!

> > > -	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);
> > 
> > Using a PAGE_SIZE multiplier here isn't a good thing...
> 
> Yes, I'll fix that in one of the next iterations.

Agreed.

> > > +	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
> > 
> > ... especially not with magic constants like this.
> 
> Yeah.  Pavel, what's at 0x3f00, btw?

struct wakeup_header.

I really need the entry point to be at offset 0, so that I can get
pointers to my data. I could not figure out how to do it any other
way. And if 0 is taken, I thought I'd put header at the end.

									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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 23:35           ` Pavel Machek
@ 2008-02-07 23:36             ` Rafael J. Wysocki
  2008-02-07 23:41               ` Pavel Machek
  2008-02-07 23:42             ` H. Peter Anvin
  1 sibling, 1 reply; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-07 23:36 UTC (permalink / raw)
  To: Pavel Machek; +Cc: H. Peter Anvin, kernel list, Linux-pm mailing list

On Friday, 8 of February 2008, Pavel Machek wrote:
> Hi!

Hi,

> > > > -	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);
> > > 
> > > Using a PAGE_SIZE multiplier here isn't a good thing...
> > 
> > Yes, I'll fix that in one of the next iterations.
> 
> Agreed.
> 
> > > > +	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
> > > 
> > > ... especially not with magic constants like this.
> > 
> > Yeah.  Pavel, what's at 0x3f00, btw?
> 
> struct wakeup_header.
> 
> I really need the entry point to be at offset 0, so that I can get
> pointers to my data. I could not figure out how to do it any other
> way. And if 0 is taken, I thought I'd put header at the end.

What does the number 0x3f00 follow from?

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 23:36             ` Rafael J. Wysocki
@ 2008-02-07 23:41               ` Pavel Machek
  0 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-07 23:41 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: H. Peter Anvin, kernel list, Linux-pm mailing list

Hi!

> > > > > +	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
> > > > 
> > > > ... especially not with magic constants like this.
> > > 
> > > Yeah.  Pavel, what's at 0x3f00, btw?
> > 
> > struct wakeup_header.
> > 
> > I really need the entry point to be at offset 0, so that I can get
> > pointers to my data. I could not figure out how to do it any other
> > way. And if 0 is taken, I thought I'd put header at the end.
> 
> What does the number 0x3f00 follow from?

wakeup.ld:

SECTIONS
{
	. = 0x3f00;
	.header		: { *(.header) }

Ok, if we can use defines, this is probably great candidate for one of
them.
									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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 23:35           ` Pavel Machek
  2008-02-07 23:36             ` Rafael J. Wysocki
@ 2008-02-07 23:42             ` H. Peter Anvin
  2008-02-08  7:04               ` Pavel Machek
  1 sibling, 1 reply; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-07 23:42 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

Pavel Machek wrote:
> 
> I really need the entry point to be at offset 0, so that I can get
> pointers to my data. I could not figure out how to do it any other
> way. And if 0 is taken, I thought I'd put header at the end.
> 

Why not just put the structure at 0, and put pointers in the structure 
to everything else you need?

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 23:42             ` H. Peter Anvin
@ 2008-02-08  7:04               ` Pavel Machek
  2008-02-08  7:40                 ` H. Peter Anvin
  2008-02-08 16:23                 ` Rafael J. Wysocki
  0 siblings, 2 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-08  7:04 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

Hi!

> >I really need the entry point to be at offset 0, so 
> >that I can get
> >pointers to my data. I could not figure out how to do 
> >it any other
> >way. And if 0 is taken, I thought I'd put header at the 
> >end.
> >
> 
> Why not just put the structure at 0, and put pointers in 
> the structure to everything else you need?

segments:offsets rear its ugly head here. I need %ds to point to my
data, and the way to do it is copy it from %cs; that needs start to be
at 0.

If you can find a solution that does not need this (some
segment/offset arithmetics at beggining of wakeup?) we could use it,
but I was lost between relocations.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08  7:04               ` Pavel Machek
@ 2008-02-08  7:40                 ` H. Peter Anvin
  2008-02-08 16:23                 ` Rafael J. Wysocki
  1 sibling, 0 replies; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-08  7:40 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

Pavel Machek wrote:
> Hi!
> 
>>> I really need the entry point to be at offset 0, so 
>>> that I can get
>>> pointers to my data. I could not figure out how to do 
>>> it any other
>>> way. And if 0 is taken, I thought I'd put header at the 
>>> end.
>>>
>> Why not just put the structure at 0, and put pointers in 
>> the structure to everything else you need?
> 
> segments:offsets rear its ugly head here. I need %ds to point to my
> data, and the way to do it is copy it from %cs; that needs start to be
> at 0.
> 
> If you can find a solution that does not need this (some
> segment/offset arithmetics at beggining of wakeup?) we could use it,
> but I was lost between relocations.
> 

Let me look at it in the morning.  Got a specific pointer?

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08  7:04               ` Pavel Machek
  2008-02-08  7:40                 ` H. Peter Anvin
@ 2008-02-08 16:23                 ` Rafael J. Wysocki
  2008-02-08 21:00                   ` Pavel Machek
  1 sibling, 1 reply; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-08 16:23 UTC (permalink / raw)
  To: Pavel Machek; +Cc: H. Peter Anvin, kernel list, Linux-pm mailing list

On Friday, 8 of February 2008, Pavel Machek wrote:
> Hi!

Hi,

> > >I really need the entry point to be at offset 0, so 
> > >that I can get
> > >pointers to my data. I could not figure out how to do 
> > >it any other
> > >way. And if 0 is taken, I thought I'd put header at the 
> > >end.
> > >
> > 
> > Why not just put the structure at 0, and put pointers in 
> > the structure to everything else you need?
> 
> segments:offsets rear its ugly head here. I need %ds to point to my
> data, and the way to do it is copy it from %cs; that needs start to be
> at 0.

Hm, why exactly is that necessay?

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 16:23                 ` Rafael J. Wysocki
@ 2008-02-08 21:00                   ` Pavel Machek
  2008-02-08 21:02                     ` H. Peter Anvin
  2008-02-08 21:20                     ` [linux-pm] " Alan Stern
  0 siblings, 2 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:00 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: H. Peter Anvin, kernel list, Linux-pm mailing list

On Fri 2008-02-08 17:23:15, Rafael J. Wysocki wrote:
> On Friday, 8 of February 2008, Pavel Machek wrote:
> > Hi!
> 
> Hi,
> 
> > > >I really need the entry point to be at offset 0, so 
> > > >that I can get
> > > >pointers to my data. I could not figure out how to do 
> > > >it any other
> > > >way. And if 0 is taken, I thought I'd put header at the 
> > > >end.
> > > >
> > > 
> > > Why not just put the structure at 0, and put pointers in 
> > > the structure to everything else you need?
> > 
> > segments:offsets rear its ugly head here. I need %ds to point to my
> > data, and the way to do it is copy it from %cs; that needs start to be
> > at 0.
> 
> Hm, why exactly is that necessay?

It is not _neccessary_. Try to come up with another method that gets
relocations right. I could not :-(.

(Actually, putting table at the offset 0 and short jump at beggining
of the table would probably do the trick. But that still keeps code at
offset 0 :-).
									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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:00                   ` Pavel Machek
@ 2008-02-08 21:02                     ` H. Peter Anvin
  2008-02-08 21:09                       ` Pavel Machek
  2008-02-08 21:20                     ` [linux-pm] " Alan Stern
  1 sibling, 1 reply; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-08 21:02 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

Pavel Machek wrote:
> On Fri 2008-02-08 17:23:15, Rafael J. Wysocki wrote:
>> On Friday, 8 of February 2008, Pavel Machek wrote:
>>> Hi!
>> Hi,
>>
>>>>> I really need the entry point to be at offset 0, so 
>>>>> that I can get
>>>>> pointers to my data. I could not figure out how to do 
>>>>> it any other
>>>>> way. And if 0 is taken, I thought I'd put header at the 
>>>>> end.
>>>>>
>>>> Why not just put the structure at 0, and put pointers in 
>>>> the structure to everything else you need?
>>> segments:offsets rear its ugly head here. I need %ds to point to my
>>> data, and the way to do it is copy it from %cs; that needs start to be
>>> at 0.
>> Hm, why exactly is that necessay?
> 
> It is not _neccessary_. Try to come up with another method that gets
> relocations right. I could not :-(.
> 
> (Actually, putting table at the offset 0 and short jump at beggining
> of the table would probably do the trick. But that still keeps code at
> offset 0 :-).
> 									Pavel

Why not just put a pointer to the start of the code in the table, and 
make an indirect call to it?

Where is this code?

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:02                     ` H. Peter Anvin
@ 2008-02-08 21:09                       ` Pavel Machek
  2008-02-08 21:18                         ` H. Peter Anvin
  0 siblings, 1 reply; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:09 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

On Fri 2008-02-08 13:02:57, H. Peter Anvin wrote:
> Pavel Machek wrote:
>> On Fri 2008-02-08 17:23:15, Rafael J. Wysocki wrote:
>>> On Friday, 8 of February 2008, Pavel Machek wrote:
>>>> Hi!
>>> Hi,
>>>
>>>>>> I really need the entry point to be at offset 0, so that I can get
>>>>>> pointers to my data. I could not figure out how to do it any other
>>>>>> way. And if 0 is taken, I thought I'd put header at the end.
>>>>>>
>>>>> Why not just put the structure at 0, and put pointers in the structure 
>>>>> to everything else you need?
>>>> segments:offsets rear its ugly head here. I need %ds to point to my
>>>> data, and the way to do it is copy it from %cs; that needs start to be
>>>> at 0.
>>> Hm, why exactly is that necessay?
>>
>> It is not _neccessary_. Try to come up with another method that gets
>> relocations right. I could not :-(.
>>
>> (Actually, putting table at the offset 0 and short jump at beggining
>> of the table would probably do the trick. But that still keeps code at
>> offset 0 :-).
>
> Why not just put a pointer to the start of the code in the table, and make 
> an indirect call to it?

Indirect call from where?

BIOS jumps to address you provide.

> Where is this code?

arch/x86/kernel/acpi/realmode/wakeup.S

BIOS jumps to wakeup_code. With CS=something, IP=0. If wakeup code is
at other address than zero, I'll not be able to easily address data
below it.
								Pavel

		.globl	wakeup_header
wakeup_header:
...
realmode_flags:	.long	0
signature:	.long	0x51ee1111
...
	.text
	.globl	_start
	.code16
wakeup_code:
_start:
	cli
	cld

	/* Set up segments */
	movw	%cs,%ax
	movw	%ax,%ds
	movw	%ax,%es
	movw	%ax,%ss

...
	/* Check header signature... */
	movl	signature, %eax
	cmpl	$0x51ee1111, %eax
	jne	bogus_real_magic



									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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:40         ` Rafael J. Wysocki
  2008-02-07 22:44           ` H. Peter Anvin
  2008-02-07 22:45           ` H. Peter Anvin
@ 2008-02-08 21:13           ` Pavel Machek
  2008-02-08 21:41             ` Maxim Levitsky
  2 siblings, 1 reply; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:13 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: kernel list, Linux-pm mailing list, H. Peter Anvin

Hi!

> > Can you post a delta against my versoin? I do not see any changes from
> > a quick glance.
> 
> Appended (plus I removed two hunks, one in arch/x86/Makefile and one in
> drivers/acpi/sleep/main.c that were unrelated to the rest of the patch).

Thanks, applied.

> > This is probably more acceptable version of beep; but there are
> > probably even better ways to clean it...
> > 
> >         if (wakeup_header.realmode_flags & 4) {
> >                 inb(97);
> >                 outb(0, 0x80);
> >                 outb(3, 97);
> >                 outb(0, 0x80);
> >                 outb(-74, 67);
> >                 outb(0, 0x80);
> >                 outb(-119, 66);
> >                 outb(0, 0x80);
> >                 outb(15, 66);
> >         }
> > 
> > ...like the version that makes beep/pause/beep/pause, so that user can
> > count them.
> 
> Can we move it into a separate function?

I guess we want to use HPA's morse 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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:09                       ` Pavel Machek
@ 2008-02-08 21:18                         ` H. Peter Anvin
  0 siblings, 0 replies; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-08 21:18 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

Pavel Machek wrote:

> 
> Indirect call from where?
> 
> BIOS jumps to address you provide.
> 
>> Where is this code?
> 
> arch/x86/kernel/acpi/realmode/wakeup.S
> 
> BIOS jumps to wakeup_code. With CS=something, IP=0. If wakeup code is
> at other address than zero, I'll not be able to easily address data
> below it.
> 								Pavel

Ah, okay.  Yes, the canonical way to deal with that is to put a short 
jump at the top.

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [linux-pm] Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:00                   ` Pavel Machek
  2008-02-08 21:02                     ` H. Peter Anvin
@ 2008-02-08 21:20                     ` Alan Stern
  2008-02-08 21:23                       ` Pavel Machek
  1 sibling, 1 reply; 62+ messages in thread
From: Alan Stern @ 2008-02-08 21:20 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Rafael J. Wysocki, Linux-pm mailing list, kernel list, H. Peter Anvin

On Fri, 8 Feb 2008, Pavel Machek wrote:

> > > segments:offsets rear its ugly head here. I need %ds to point to my
> > > data, and the way to do it is copy it from %cs; that needs start to be
> > > at 0.
> > 
> > Hm, why exactly is that necessay?
> 
> It is not _neccessary_. Try to come up with another method that gets
> relocations right. I could not :-(.
> 
> (Actually, putting table at the offset 0 and short jump at beggining
> of the table would probably do the trick. But that still keeps code at
> offset 0 :-).

Pavel, can you explain in greater detail exactly what you need?

It sounds like you are running in real mode with code stored at some 
(unknown?) location in memory.  The BIOS calls this code with IP=0 and 
CS=<something>, which apparently doesn't fit your requirements.

So just what are your requirements?  The only possibilities I can think 
of are:

	Code stored at a particular location in memory;

	CS, IP, etc. initialized to some particular values.

What am I missing?

Alan Stern


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [linux-pm] Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:20                     ` [linux-pm] " Alan Stern
@ 2008-02-08 21:23                       ` Pavel Machek
  2008-02-08 21:27                         ` H. Peter Anvin
  0 siblings, 1 reply; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:23 UTC (permalink / raw)
  To: Alan Stern
  Cc: Rafael J. Wysocki, Linux-pm mailing list, kernel list, H. Peter Anvin

Hi!

> > > > segments:offsets rear its ugly head here. I need %ds to point to my
> > > > data, and the way to do it is copy it from %cs; that needs start to be
> > > > at 0.
> > > 
> > > Hm, why exactly is that necessay?
> > 
> > It is not _neccessary_. Try to come up with another method that gets
> > relocations right. I could not :-(.
> > 
> > (Actually, putting table at the offset 0 and short jump at beggining
> > of the table would probably do the trick. But that still keeps code at
> > offset 0 :-).
> 
> Pavel, can you explain in greater detail exactly what you need?

I do not think I need anything. I'm just explaining why data need to
go at nonzero offset. Nothing to see here, move on ;-).

> It sounds like you are running in real mode with code stored at some 
> (unknown?) location in memory.  The BIOS calls this code with IP=0 and 
> CS=<something>, which apparently doesn't fit your requirements.

> So just what are your requirements?  The only possibilities I can think 
> of are:
> 
> 	Code stored at a particular location in memory;
> 
> 	CS, IP, etc. initialized to some particular values.
> 
> What am I missing?

See arch/x86/kernel/acpi/realmode/wakeup.S (the version that was sent
to the list). No problem there, but table stored at nonzero
offset. Short jump at the beggining of table would fix it (ugly).

									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] 62+ messages in thread

* Re: [linux-pm] Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:23                       ` Pavel Machek
@ 2008-02-08 21:27                         ` H. Peter Anvin
  2008-02-08 21:31                           ` Pavel Machek
  0 siblings, 1 reply; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-08 21:27 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Alan Stern, Rafael J. Wysocki, Linux-pm mailing list, kernel list

Pavel Machek wrote:
> 
> See arch/x86/kernel/acpi/realmode/wakeup.S (the version that was sent
> to the list). No problem there, but table stored at nonzero
> offset. Short jump at the beggining of table would fix it (ugly).
> 

Ugly, but it's the standard way to deal.  We have it in the bzImage 
format, too.

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [linux-pm] Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:27                         ` H. Peter Anvin
@ 2008-02-08 21:31                           ` Pavel Machek
  2008-02-08 21:56                             ` Rafael J. Wysocki
  0 siblings, 1 reply; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:31 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Alan Stern, Rafael J. Wysocki, Linux-pm mailing list, kernel list

On Fri 2008-02-08 13:27:30, H. Peter Anvin wrote:
> Pavel Machek wrote:
>>
>> See arch/x86/kernel/acpi/realmode/wakeup.S (the version that was sent
>> to the list). No problem there, but table stored at nonzero
>> offset. Short jump at the beggining of table would fix it (ugly).
>>
>
> Ugly, but it's the standard way to deal.  We have it in the bzImage format, 
> too.

I'd prefer to keep it as it is, there are no problems.

This way, we can put debugging instructions at the first byte of
wakeup code, which is somehow important.

Plus, with right #defines, it should be clean enough.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:28       ` Sam Ravnborg
  2008-02-07 22:34         ` H. Peter Anvin
@ 2008-02-08 21:31         ` Pavel Machek
  2008-02-08 21:34         ` Pavel Machek
                           ` (2 subsequent siblings)
  4 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:31 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list, H. Peter Anvin

On Thu 2008-02-07 23:28:33, Sam Ravnborg wrote:
> > ===================================================================
> > --- /dev/null
> > +++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.ld
> > @@ -0,0 +1,51 @@
> > +/*
> > + * 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) }
> 
> Can we please use C style in this file.
> Like this:

Commiting now :-).
						Pavel

diff --git a/arch/x86/kernel/acpi/realmode/wakeup.ld b/arch/x86/kernel/acpi/realmode/wakeup.ld
index 5dff2f0..1a1e755 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.ld
+++ b/arch/x86/kernel/acpi/realmode/wakeup.ld
@@ -10,31 +10,38 @@ ENTRY(_start)
 SECTIONS
 {
 	. = 0x3f00;
-	.header		: { *(.header) }
+	.header : {
+		 *(.header)
+	}
 
 	. = 0;
-	.text		: { *(.text*) }
+	.text : {
+		 *(.text*)
+	}
 
 	. = ALIGN(16);
-	.rodata		: { *(.rodata*) }
+	.rodata : {
+		*(.rodata*)
+	}
 
-	.videocards	: {
+	.videocards : {
 		video_cards = .;
 		*(.videocards)
 		video_cards_end = .;
 	}
 
 	. = ALIGN(16);
-	.data		: { *(.data*) }
+	.data : {
+		 *(.data*)
+	}
 
-	.signature	: {
+	.signature : {
 		end_signature = .;
 		LONG(0x65a22c82)
 	}
 
 	. = ALIGN(16);
-	.bss		:
-	{
+	.bss :	{
 		__bss_start = .;
 		*(.bss)
 		__bss_end = .;
@@ -43,7 +50,9 @@ SECTIONS
 	. = ALIGN(16);
 	_end = .;
 
-	/DISCARD/ : { *(.note*) }
+	/DISCARD/ : {
+		*(.note*)
+	}
 
 	/* Adjust this as appropriate */
 	/* This allows 4 pages (16K) */



> 
> {
> 	.header : {
> 		*(.header)
> 	}
> 
> It is not as short as the above but it pays of to keep
> an consistent style in the whole file and across
> different .lds files.
> 
> And for good measure name it wakeup.lds.
> 
> Do we never need data from a .h file?
> If we do name it wakeup.lds.S and kbuild
> will fix it (assuming we have wakeup.lds
> as a prerequisite where it is needed.
> 
> > +
> > +	. = 0;
> > +	.text		: { *(.text*) }
> > +
> > +	. = ALIGN(16);
> Why?
> > +	.rodata		: { *(.rodata*) }
> > +
> > +	.videocards	: {
> > +		video_cards = .;
> > +		*(.videocards)
> > +		video_cards_end = .;
> > +	}
> > +
> > +	. = ALIGN(16);
> Why?
> > +	.data		: { *(.data*) }
> > +
> > +	.signature	: {
> > +		end_signature = .;
> > +		LONG(0x65a22c82)
> > +	}
> > +
> > +	. = ALIGN(16);
> Why?
> > +	.bss		:
> > +	{
> > +		__bss_start = .;
> > +		*(.bss)
> > +		__bss_end = .;
> > +	}
> > +
> > +	. = ALIGN(16);
> Why?
> > +	_end = .;
> > +
> > +	/DISCARD/ : { *(.note*) }
> > +
> > +	/* Adjust this as appropriate */
> > +	/* This allows 4 pages (16K) */
> > +	. = ASSERT(_end <= 0x4000, "Wakeup too big!");
> PAGE_SIZE * 4?
> 
> 
> 	Sam

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:28       ` Sam Ravnborg
  2008-02-07 22:34         ` H. Peter Anvin
  2008-02-08 21:31         ` Pavel Machek
@ 2008-02-08 21:34         ` Pavel Machek
  2008-02-08 21:41         ` Pavel Machek
  2008-02-08 21:49         ` Pavel Machek
  4 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:34 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list, H. Peter Anvin

Hi!

> And for good measure name it wakeup.lds.
> 
> Do we never need data from a .h file?
> If we do name it wakeup.lds.S and kbuild
> will fix it (assuming we have wakeup.lds
> as a prerequisite where it is needed.

This does not work for me. gas (or someone?) puts # comments on the
beggining of wakeup.lds, and I get compile failure. Yes, I'd like to
have it preprocessed.

# 1 "/data/l/linux/arch/x86/kernel/acpi/realmode/wakeup.lds.S"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "./include/linux/autoconf.h" 1
# 1 "<command line>" 2
# 1 "/data/l/linux/arch/x86/kernel/acpi/realmode/wakeup.lds.S"





OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(1)
ENTRY(_start)
....

ld:arch/x86/kernel/acpi/realmode/wakeup.lds:1: ignoring invalid
character `#' in expression
ld:arch/x86/kernel/acpi/realmode/wakeup.lds:1: syntax error


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 23:14             ` H. Peter Anvin
@ 2008-02-08 21:35               ` Pavel Machek
  0 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:35 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

Hi!

> Okay, this uses the iodelay as the timesource... here is the total 
> silliness (and totally untested, of course.)

Why untested? Testing suspend is easy ;-). s2ram from suspend.sf.net
tends to just work...
								Pavel

> static inline void io_delay(void)
> {
> 	outb(0, 0x80);
> }
> 
> static void udelay(int loops)
> {
> 	while (loops--)
> 		io_delay();	/* Approximately 1 us */
> }
> 
> static void beep(unsigned int hz)
> {
> 	u8 enable;
> 
> 	if (!hz) {
> 		enable = 0x00;		/* Turn off speaker */
> 	} else {
> 		u16 div = 1193181/hz;
> 
> 		outb(0xb6, 0x43);	/* Ctr 2, squarewave, load, binary */
> 		io_delay();
> 		outb(div, 0x42);	/* LSB of counter */
> 		io_delay();
> 		outb(div >> 8, 0x42);	/* MSB of counter */
> 		io_delay();
> 
> 		enable = 0x03;		/* Turn on speaker */
> 	}
> 	inb(0x61);		/* Dummy read of System Control Port B */
> 	io_delay();
> 	outb(enable, 0x61);	/* Enable timer 2 output to speaker */
> 	io_delay();
> }
> 
> #define DOT_HZ		880
> #define DASH_HZ		587
> #define US_PER_DOT	125000
> 
> /* Okay, this is totally silly, but it's kind of fun. */
> void send_morse(const char *pattern)
> {
> 	char s;
> 
> 	while ((s = *pattern++)) {
> 		switch (s) {
> 		case '.':
> 			beep(DOT_HZ);
> 			udelay(US_PER_DOT);
> 			beep(0);
> 			udelay(US_PER_DOT);
> 			break;
> 		case '-':
> 			beep(DASH_HZ);
> 			udelay(US_PER_DOT*3);
> 			beep(0);
> 			udelay(US_PER_DOT);
> 			break;
> 		default:	/* Assume it's a space */
> 			udelay(US_PER_DOT*3);
> 			break;
> 		}
> 	}
> }
> 
> 


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:28       ` Sam Ravnborg
                           ` (2 preceding siblings ...)
  2008-02-08 21:34         ` Pavel Machek
@ 2008-02-08 21:41         ` Pavel Machek
  2008-02-08 21:47           ` Sam Ravnborg
  2008-02-08 21:49         ` Pavel Machek
  4 siblings, 1 reply; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:41 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list, H. Peter Anvin

> Do we never need data from a .h file?
> If we do name it wakeup.lds.S and kbuild
> will fix it (assuming we have wakeup.lds
> as a prerequisite where it is needed.

Ok, I got it to work... but notice the ugly #undef :-(.

							Pavel

diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile
index b239f0f..0e4742b 100644
--- a/arch/x86/kernel/acpi/realmode/Makefile
+++ b/arch/x86/kernel/acpi/realmode/Makefile
@@ -46,7 +46,10 @@ KBUILD_AFLAGS	:= $(KBUILD_CFLAGS) -D__AS
 WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
 
 LDFLAGS_wakeup.elf	:= -T
-$(obj)/wakeup.elf: $(src)/wakeup.ld $(WAKEUP_OBJS) FORCE
+
+CPPFLAGS_wakeup.lds += -P -C
+
+$(obj)/wakeup.elf: $(src)/wakeup.lds $(WAKEUP_OBJS) FORCE
 	$(call if_changed,ld)
 
 OBJCOPYFLAGS_wakeup.bin	:= -O binary
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.ld b/arch/x86/kernel/acpi/realmode/wakeup.ld
deleted file mode 100644
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
@@ -0,0 +1,62 @@
+/*
+ * wakeup.ld
+ *
+ * Linker script for the real-mode wakeup code
+ */
+#undef i386
+
+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!");
+}


> > +
> > +	. = 0;
> > +	.text		: { *(.text*) }
> > +
> > +	. = ALIGN(16);
> Why?
> > +	.rodata		: { *(.rodata*) }
> > +
> > +	.videocards	: {
> > +		video_cards = .;
> > +		*(.videocards)
> > +		video_cards_end = .;
> > +	}
> > +
> > +	. = ALIGN(16);
> Why?
> > +	.data		: { *(.data*) }
> > +
> > +	.signature	: {
> > +		end_signature = .;
> > +		LONG(0x65a22c82)
> > +	}
> > +
> > +	. = ALIGN(16);
> Why?
> > +	.bss		:
> > +	{
> > +		__bss_start = .;
> > +		*(.bss)
> > +		__bss_end = .;
> > +	}
> > +
> > +	. = ALIGN(16);
> Why?
> > +	_end = .;
> > +
> > +	/DISCARD/ : { *(.note*) }
> > +
> > +	/* Adjust this as appropriate */
> > +	/* This allows 4 pages (16K) */
> > +	. = ASSERT(_end <= 0x4000, "Wakeup too big!");
> PAGE_SIZE * 4?
> 
> 
> 	Sam

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:13           ` Pavel Machek
@ 2008-02-08 21:41             ` Maxim Levitsky
  2008-02-08 21:51               ` Pavel Machek
  0 siblings, 1 reply; 62+ messages in thread
From: Maxim Levitsky @ 2008-02-08 21:41 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list, H. Peter Anvin

On Friday, 8 February 2008 23:13:46 Pavel Machek wrote:
> Hi!
> 
> > > Can you post a delta against my versoin? I do not see any changes from
> > > a quick glance.
> > 
> > Appended (plus I removed two hunks, one in arch/x86/Makefile and one in
> > drivers/acpi/sleep/main.c that were unrelated to the rest of the patch).
> 
> Thanks, applied.
> 
> > > This is probably more acceptable version of beep; but there are
> > > probably even better ways to clean it...
> > > 
> > >         if (wakeup_header.realmode_flags & 4) {
> > >                 inb(97);
> > >                 outb(0, 0x80);
> > >                 outb(3, 97);
> > >                 outb(0, 0x80);
> > >                 outb(-74, 67);
> > >                 outb(0, 0x80);
> > >                 outb(-119, 66);
> > >                 outb(0, 0x80);
> > >                 outb(15, 66);
> > >         }
> > > 
> > > ...like the version that makes beep/pause/beep/pause, so that user can
> > > count them.
> > 
> > Can we move it into a separate function?
> 
> I guess we want to use HPA's morse code ;-).
> 									Pavel

Seriously, why not...
For decades BIOSes have used sound beeps to tell the user about a early problem
that happened have before video is initialized.

Maybe not a long messages using morse code, but at least
you can have several messages to tell the user about different problems in the boot code

like

two short beeps for an oops
1 short beep for normal resume (so the user will know that the video is to blame)

and so on.

I don't know morse code, but I probably would have learn it.
Once I had very nasty problem with resume, a hang, but only sometimes,
and I had to play with rtc to debug it, and still I couldn't figure out
what was wrong.

Fortunately, this problem disappeared (was somehow fixed).
For reference take a look at http://lkml.org/lkml/2007/3/17/155

I remember that I did about 1500 reboots to try to fix this.
(According to hard disk's 'smart' statistics)



Suggestion: the speaker usually is quite loud, thus it can be annoying to use
for morse code or so.
Why not to use keyboard leds for this purpose?
(USB keyboard probably isn't an option, but user can always pull an old PC keyboard
out of closet, and use it)


Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:41         ` Pavel Machek
@ 2008-02-08 21:47           ` Sam Ravnborg
  0 siblings, 0 replies; 62+ messages in thread
From: Sam Ravnborg @ 2008-02-08 21:47 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list, H. Peter Anvin

On Fri, Feb 08, 2008 at 10:41:45PM +0100, Pavel Machek wrote:
> > Do we never need data from a .h file?
> > If we do name it wakeup.lds.S and kbuild
> > will fix it (assuming we have wakeup.lds
> > as a prerequisite where it is needed.
> 
> Ok, I got it to work... but notice the ugly #undef :-(.
Great.
We have the same issue with vmlinux_64.lds.S in x86/kernel/

	Sam

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:28       ` Sam Ravnborg
                           ` (3 preceding siblings ...)
  2008-02-08 21:41         ` Pavel Machek
@ 2008-02-08 21:49         ` Pavel Machek
  4 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:49 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list, H. Peter Anvin

Hi!

This cleans up .lds, making use of constants...

								Pavel

diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h
index 4a26e27..ee7c68b 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.h
+++ b/arch/x86/kernel/acpi/realmode/wakeup.h
@@ -6,6 +6,7 @@
 #ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
 #define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
 
+#ifndef __ASSEMBLY__
 #include <linux/types.h>
 
 /* This must match data at wakeup.S */
@@ -27,5 +28,10 @@ struct wakeup_header {
 	u16 trampoline_segment;
 	u32 signature;		/* To check we have correct structure */
 } __attribute__((__packed__));
+#endif
+
+#define HEADER_OFFSET 0x3f00
+#define WAKEUP_SIZE   0x4000
+
 
 #endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
index 24ebe75..22fab6c 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.lds.S
+++ b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
@@ -4,6 +4,7 @@
  * Linker script for the real-mode wakeup code
  */
 #undef i386
+#include "wakeup.h"
 
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
@@ -11,7 +12,7 @@ ENTRY(_start)
 
 SECTIONS
 {
-	. = 0x3f00;
+	. = HEADER_OFFSET;
 	.header : {
 		 *(.header)
 	}
@@ -56,7 +57,5 @@ SECTIONS
 		*(.note*)
 	}
 
-	/* Adjust this as appropriate */
-	/* This allows 4 pages (16K) */
-	. = ASSERT(_end <= 0x4000, "Wakeup too big!");
+	. = ASSERT(_end <= WAKEUP_SIZE, "Wakeup too big!");
 }
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 1b282b1..561565e 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -53,9 +53,9 @@ int acpi_save_state_mem(void)
 		       "S3 disabled\n");
 		return -ENOMEM;
 	}
-	memcpy((void *)acpi_realmode, &wakeup_code_start, 4*PAGE_SIZE);
+	memcpy((void *)acpi_realmode, &wakeup_code_start, WAKEUP_SIZE);
 
-	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
+	header = (struct wakeup_header *)(acpi_realmode + HEADER_OFFSET);
 	if (header->signature != 0x51ee1111) {
 		printk(KERN_ERR "wakeup header does not match\n");
 		return -EINVAL;
@@ -111,13 +111,13 @@ void acpi_restore_state_mem(void)
  */
 void __init acpi_reserve_bootmem(void)
 {
-	if ((&wakeup_code_end - &wakeup_code_start) > PAGE_SIZE*4) {
+	if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) {
 		printk(KERN_ERR
 		       "ACPI: Wakeup code way too big, S3 disabled.\n");
 		return;
 	}
 
-	acpi_realmode = (unsigned long)alloc_bootmem_low(PAGE_SIZE*4);
+	acpi_realmode = (unsigned long)alloc_bootmem_low(WAKEUP_SIZE);
 
 	if (!acpi_realmode) {
 		printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");




-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:41             ` Maxim Levitsky
@ 2008-02-08 21:51               ` Pavel Machek
  0 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:51 UTC (permalink / raw)
  To: Maxim Levitsky
  Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list, H. Peter Anvin

Hi!

> I remember that I did about 1500 reboots to try to fix this.
> (According to hard disk's 'smart' statistics)

Poor you.

> Suggestion: the speaker usually is quite loud, thus it can be annoying to use
> for morse code or so.
> Why not to use keyboard leds for this purpose?
> (USB keyboard probably isn't an option, but user can always pull an old PC keyboard
> out of closet, and use it)

IIRC keyboard leds are quite hard to drive, plus decoding audible
morse is easier than blinkenlights...
									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] 62+ messages in thread

* Re: [linux-pm] Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:31                           ` Pavel Machek
@ 2008-02-08 21:56                             ` Rafael J. Wysocki
  2008-02-08 21:59                               ` Pavel Machek
  0 siblings, 1 reply; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-08 21:56 UTC (permalink / raw)
  To: Pavel Machek
  Cc: H. Peter Anvin, Alan Stern, Linux-pm mailing list, kernel list,
	Sam Ravnborg

On Friday, 8 of February 2008, Pavel Machek wrote:
> On Fri 2008-02-08 13:27:30, H. Peter Anvin wrote:
> > Pavel Machek wrote:
> >>
> >> See arch/x86/kernel/acpi/realmode/wakeup.S (the version that was sent
> >> to the list). No problem there, but table stored at nonzero
> >> offset. Short jump at the beggining of table would fix it (ugly).
> >>
> >
> > Ugly, but it's the standard way to deal.  We have it in the bzImage format, 
> > too.
> 
> I'd prefer to keep it as it is, there are no problems.
> 
> This way, we can put debugging instructions at the first byte of
> wakeup code, which is somehow important.
> 
> Plus, with right #defines, it should be clean enough.

Well, I don't know how to evaluate #defines in *.ld files ...

Rafael

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:38       ` H. Peter Anvin
  2008-02-07 23:06         ` Rafael J. Wysocki
@ 2008-02-08 21:56         ` Pavel Machek
  2008-02-08 21:58         ` Pavel Machek
  2 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:56 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

Hi!

>> +	.section ".header", "a"
>> +
>> +/* This should match the structure in wakeup.h */
>> +		.globl	wakeup_header
>> +wakeup_header:
>> +video_mode:	.short	0	/* Video mode number */
>> +pmode_return:	.byte	0x66, 0xea	/* ljmpl */
>> +		.long	0	/* offset goes here */
>> +		.short	__KERNEL_CS
>
> Missing a .short pad here... Pavel fixed that at some point, I thought.

No pad needed, AFAICT.

>>  	}
>> -	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);
>
> Using a PAGE_SIZE multiplier here isn't a good thing...

Fixed.

>> +	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
>
> ... especially not with magic constants like this.

Fixed.

> If you're putting the "header" at the end, then you should also replace the 
> end_signature stuff since that's, then, redundant.  Furthermore, by doing 
> so, you're also padding the binary out to its maximum length, so you might 
> as well just remove the .bss-clearing stuff.

Good, lets remove bss clearing.

>> +	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);
>> +	}
>
> Yes, why not save EFER every time?

Dunno, I copied it from other code, and as it depends on nx setting,
I'd prefer not to touch it for now. Do old CPUs have EFER?

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-07 22:38       ` H. Peter Anvin
  2008-02-07 23:06         ` Rafael J. Wysocki
  2008-02-08 21:56         ` Pavel Machek
@ 2008-02-08 21:58         ` Pavel Machek
  2008-02-08 22:01           ` Rafael J. Wysocki
  2 siblings, 1 reply; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:58 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list

Hi!

Rafael, this is for you. My cleanups, relative to your cleanup
patch. You may need manual patching around rep/stosd.

								Pavel

diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile
index b239f0f..0e4742b 100644
--- a/arch/x86/kernel/acpi/realmode/Makefile
+++ b/arch/x86/kernel/acpi/realmode/Makefile
@@ -46,7 +46,10 @@ KBUILD_AFLAGS	:= $(KBUILD_CFLAGS) -D__AS
 WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
 
 LDFLAGS_wakeup.elf	:= -T
-$(obj)/wakeup.elf: $(src)/wakeup.ld $(WAKEUP_OBJS) FORCE
+
+CPPFLAGS_wakeup.lds += -P -C
+
+$(obj)/wakeup.elf: $(src)/wakeup.lds $(WAKEUP_OBJS) FORCE
 	$(call if_changed,ld)
 
 OBJCOPYFLAGS_wakeup.bin	:= -O binary
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S
index 26145c0..edff763 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.S
+++ b/arch/x86/kernel/acpi/realmode/wakeup.S
@@ -56,14 +56,6 @@ _start:
 	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
 
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h
index 4a26e27..6a49435 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.h
+++ b/arch/x86/kernel/acpi/realmode/wakeup.h
@@ -6,12 +6,11 @@
 #ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
 #define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
 
+#ifndef __ASSEMBLY__
 #include <linux/types.h>
 
 /* This must match data at wakeup.S */
 struct wakeup_header {
-	u16 entry;		/* unused */
-	u16 total;		/* unused */
 	u16 video_mode;		/* Video mode number */
 	u16 _jmp1;
 	u32 pmode_entry;	/* Protected mode resume point */
@@ -27,5 +26,10 @@ struct wakeup_header {
 	u16 trampoline_segment;
 	u32 signature;		/* To check we have correct structure */
 } __attribute__((__packed__));
+#endif
+
+#define HEADER_OFFSET 0x3f00
+#define WAKEUP_SIZE   0x4000
+
 
 #endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.ld b/arch/x86/kernel/acpi/realmode/wakeup.ld
deleted file mode 100644
index 5dff2f0..0000000
--- a/arch/x86/kernel/acpi/realmode/wakeup.ld
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
new file mode 100644
index 0000000..22fab6c
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
@@ -0,0 +1,61 @@
+/*
+ * wakeup.ld
+ *
+ * Linker script for the real-mode wakeup code
+ */
+#undef i386
+#include "wakeup.h"
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = HEADER_OFFSET;
+	.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*)
+	}
+
+	. = ASSERT(_end <= WAKEUP_SIZE, "Wakeup too big!");
+}
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 1b282b1..561565e 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -53,9 +53,9 @@ int acpi_save_state_mem(void)
 		       "S3 disabled\n");
 		return -ENOMEM;
 	}
-	memcpy((void *)acpi_realmode, &wakeup_code_start, 4*PAGE_SIZE);
+	memcpy((void *)acpi_realmode, &wakeup_code_start, WAKEUP_SIZE);
 
-	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
+	header = (struct wakeup_header *)(acpi_realmode + HEADER_OFFSET);
 	if (header->signature != 0x51ee1111) {
 		printk(KERN_ERR "wakeup header does not match\n");
 		return -EINVAL;
@@ -111,13 +111,13 @@ void acpi_restore_state_mem(void)
  */
 void __init acpi_reserve_bootmem(void)
 {
-	if ((&wakeup_code_end - &wakeup_code_start) > PAGE_SIZE*4) {
+	if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) {
 		printk(KERN_ERR
 		       "ACPI: Wakeup code way too big, S3 disabled.\n");
 		return;
 	}
 
-	acpi_realmode = (unsigned long)alloc_bootmem_low(PAGE_SIZE*4);
+	acpi_realmode = (unsigned long)alloc_bootmem_low(WAKEUP_SIZE);
 
 	if (!acpi_realmode) {
 		printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [linux-pm] Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:56                             ` Rafael J. Wysocki
@ 2008-02-08 21:59                               ` Pavel Machek
  0 siblings, 0 replies; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 21:59 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: H. Peter Anvin, Alan Stern, Linux-pm mailing list, kernel list,
	Sam Ravnborg

On Fri 2008-02-08 22:56:08, Rafael J. Wysocki wrote:
> On Friday, 8 of February 2008, Pavel Machek wrote:
> > On Fri 2008-02-08 13:27:30, H. Peter Anvin wrote:
> > > Pavel Machek wrote:
> > >>
> > >> See arch/x86/kernel/acpi/realmode/wakeup.S (the version that was sent
> > >> to the list). No problem there, but table stored at nonzero
> > >> offset. Short jump at the beggining of table would fix it (ugly).
> > >>
> > >
> > > Ugly, but it's the standard way to deal.  We have it in the bzImage format, 
> > > too.
> > 
> > I'd prefer to keep it as it is, there are no problems.
> > 
> > This way, we can put debugging instructions at the first byte of
> > wakeup code, which is somehow important.
> > 
> > Plus, with right #defines, it should be clean enough.
> 
> Well, I don't know how to evaluate #defines in *.ld files ...

See a patch in your inbox :-). Sam told me how to do it.
									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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 21:58         ` Pavel Machek
@ 2008-02-08 22:01           ` Rafael J. Wysocki
  2008-02-08 22:08             ` Pavel Machek
  0 siblings, 1 reply; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-08 22:01 UTC (permalink / raw)
  To: Pavel Machek; +Cc: H. Peter Anvin, kernel list, Linux-pm mailing list

On Friday, 8 of February 2008, Pavel Machek wrote:
> Hi!
> 
> Rafael, this is for you.

Thanks.

> My cleanups, relative to your cleanup patch. You may need manual patching
> around rep/stosd.

OK, I'll try to merge it.

Rafael


> diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile
> index b239f0f..0e4742b 100644
> --- a/arch/x86/kernel/acpi/realmode/Makefile
> +++ b/arch/x86/kernel/acpi/realmode/Makefile
> @@ -46,7 +46,10 @@ KBUILD_AFLAGS	:= $(KBUILD_CFLAGS) -D__AS
>  WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
>  
>  LDFLAGS_wakeup.elf	:= -T
> -$(obj)/wakeup.elf: $(src)/wakeup.ld $(WAKEUP_OBJS) FORCE
> +
> +CPPFLAGS_wakeup.lds += -P -C
> +
> +$(obj)/wakeup.elf: $(src)/wakeup.lds $(WAKEUP_OBJS) FORCE
>  	$(call if_changed,ld)
>  
>  OBJCOPYFLAGS_wakeup.bin	:= -O binary
> diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S
> index 26145c0..edff763 100644
> --- a/arch/x86/kernel/acpi/realmode/wakeup.S
> +++ b/arch/x86/kernel/acpi/realmode/wakeup.S
> @@ -56,14 +56,6 @@ _start:
>  	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
>  
> diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h
> index 4a26e27..6a49435 100644
> --- a/arch/x86/kernel/acpi/realmode/wakeup.h
> +++ b/arch/x86/kernel/acpi/realmode/wakeup.h
> @@ -6,12 +6,11 @@
>  #ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
>  #define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
>  
> +#ifndef __ASSEMBLY__
>  #include <linux/types.h>
>  
>  /* This must match data at wakeup.S */
>  struct wakeup_header {
> -	u16 entry;		/* unused */
> -	u16 total;		/* unused */
>  	u16 video_mode;		/* Video mode number */
>  	u16 _jmp1;
>  	u32 pmode_entry;	/* Protected mode resume point */
> @@ -27,5 +26,10 @@ struct wakeup_header {
>  	u16 trampoline_segment;
>  	u32 signature;		/* To check we have correct structure */
>  } __attribute__((__packed__));
> +#endif
> +
> +#define HEADER_OFFSET 0x3f00
> +#define WAKEUP_SIZE   0x4000
> +
>  
>  #endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
> diff --git a/arch/x86/kernel/acpi/realmode/wakeup.ld b/arch/x86/kernel/acpi/realmode/wakeup.ld
> deleted file mode 100644
> index 5dff2f0..0000000
> --- a/arch/x86/kernel/acpi/realmode/wakeup.ld
> +++ /dev/null
> @@ -1,51 +0,0 @@
> -/*
> - * 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/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
> new file mode 100644
> index 0000000..22fab6c
> --- /dev/null
> +++ b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
> @@ -0,0 +1,61 @@
> +/*
> + * wakeup.ld
> + *
> + * Linker script for the real-mode wakeup code
> + */
> +#undef i386
> +#include "wakeup.h"
> +
> +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
> +OUTPUT_ARCH(i386)
> +ENTRY(_start)
> +
> +SECTIONS
> +{
> +	. = HEADER_OFFSET;
> +	.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*)
> +	}
> +
> +	. = ASSERT(_end <= WAKEUP_SIZE, "Wakeup too big!");
> +}
> diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
> index 1b282b1..561565e 100644
> --- a/arch/x86/kernel/acpi/sleep.c
> +++ b/arch/x86/kernel/acpi/sleep.c
> @@ -53,9 +53,9 @@ int acpi_save_state_mem(void)
>  		       "S3 disabled\n");
>  		return -ENOMEM;
>  	}
> -	memcpy((void *)acpi_realmode, &wakeup_code_start, 4*PAGE_SIZE);
> +	memcpy((void *)acpi_realmode, &wakeup_code_start, WAKEUP_SIZE);
>  
> -	header = (struct wakeup_header *)(acpi_realmode + 0x3f00);
> +	header = (struct wakeup_header *)(acpi_realmode + HEADER_OFFSET);
>  	if (header->signature != 0x51ee1111) {
>  		printk(KERN_ERR "wakeup header does not match\n");
>  		return -EINVAL;
> @@ -111,13 +111,13 @@ void acpi_restore_state_mem(void)
>   */
>  void __init acpi_reserve_bootmem(void)
>  {
> -	if ((&wakeup_code_end - &wakeup_code_start) > PAGE_SIZE*4) {
> +	if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) {
>  		printk(KERN_ERR
>  		       "ACPI: Wakeup code way too big, S3 disabled.\n");
>  		return;
>  	}
>  
> -	acpi_realmode = (unsigned long)alloc_bootmem_low(PAGE_SIZE*4);
> +	acpi_realmode = (unsigned long)alloc_bootmem_low(WAKEUP_SIZE);
>  
>  	if (!acpi_realmode) {
>  		printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");
> 
> 



-- 
"Premature optimization is the root of all evil." - Donald Knuth

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 22:01           ` Rafael J. Wysocki
@ 2008-02-08 22:08             ` Pavel Machek
  2008-02-09  0:18               ` Rafael J. Wysocki
  0 siblings, 1 reply; 62+ messages in thread
From: Pavel Machek @ 2008-02-08 22:08 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: H. Peter Anvin, kernel list, Linux-pm mailing list

On Fri 2008-02-08 23:01:51, Rafael J. Wysocki wrote:
> On Friday, 8 of February 2008, Pavel Machek wrote:
> > Hi!
> > 
> > Rafael, this is for you.
> 
> Thanks.
> 
> > My cleanups, relative to your cleanup patch. You may need manual patching
> > around rep/stosd.
> 
> OK, I'll try to merge it.

For the record, now it is even tested on 32-bit and test-compiled on
64-bit.

									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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-08 22:08             ` Pavel Machek
@ 2008-02-09  0:18               ` Rafael J. Wysocki
  2008-02-09  0:32                 ` H. Peter Anvin
  0 siblings, 1 reply; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-09  0:18 UTC (permalink / raw)
  To: Pavel Machek
  Cc: H. Peter Anvin, kernel list, Linux-pm mailing list, Sam Ravnborg

On Friday, 8 of February 2008, Pavel Machek wrote:
> On Fri 2008-02-08 23:01:51, Rafael J. Wysocki wrote:
> > On Friday, 8 of February 2008, Pavel Machek wrote:
> > > Hi!
> > > 
> > > Rafael, this is for you.
> > 
> > Thanks.
> > 
> > > My cleanups, relative to your cleanup patch. You may need manual patching
> > > around rep/stosd.
> > 
> > OK, I'll try to merge it.
> 
> For the record, now it is even tested on 32-bit and test-compiled on
> 64-bit.

Consolidated patch is appended.  I'll test it tomorrow on x86-64.

I'd like to add the cleaned up beeping code to it and perhaps try to push it
for -mm testing without any further changes.  We can still do more cleanups in
followup patches.

Thanks,
Rafael


---
 arch/x86/boot/Makefile                     |    2 
 arch/x86/boot/boot.h                       |    5 
 arch/x86/boot/video-bios.c                 |    6 
 arch/x86/boot/video-mode.c                 |  173 ++++++++++++++++
 arch/x86/boot/video-vesa.c                 |    8 
 arch/x86/boot/video-vga.c                  |   12 -
 arch/x86/boot/video.c                      |  157 --------------
 arch/x86/kernel/acpi/Makefile              |    9 
 arch/x86/kernel/acpi/realmode/Makefile     |   58 +++++
 arch/x86/kernel/acpi/realmode/copy.S       |    1 
 arch/x86/kernel/acpi/realmode/video-bios.c |    1 
 arch/x86/kernel/acpi/realmode/video-mode.c |    1 
 arch/x86/kernel/acpi/realmode/video-vesa.c |    1 
 arch/x86/kernel/acpi/realmode/video-vga.c  |    1 
 arch/x86/kernel/acpi/realmode/wakemain.c   |   26 ++
 arch/x86/kernel/acpi/realmode/wakeup.S     |  113 ++++++++++
 arch/x86/kernel/acpi/realmode/wakeup.h     |   35 +++
 arch/x86/kernel/acpi/realmode/wakeup.lds.S |   61 +++++
 arch/x86/kernel/acpi/sleep.c               |   80 ++++++-
 arch/x86/kernel/acpi/wakeup_32.S           |  245 +---------------------
 arch/x86/kernel/acpi/wakeup_64.S           |  313 -----------------------------
 arch/x86/kernel/acpi/wakeup_rm.S           |   10 
 arch/x86/kernel/head_64.S                  |    4 
 arch/x86/kernel/setup_32.c                 |    4 
 arch/x86/kernel/smpboot_64.c               |   10 
 25 files changed, 624 insertions(+), 712 deletions(-)

Index: linux-2.6/arch/x86/boot/Makefile
===================================================================
--- linux-2.6.orig/arch/x86/boot/Makefile
+++ linux-2.6/arch/x86/boot/Makefile
@@ -30,7 +30,7 @@ subdir-		:= compressed
 
 setup-y		+= a20.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
+setup-y		+= printf.o string.o tty.o video.o video-mode.o version.o
 setup-$(CONFIG_X86_APM_BOOT) += apm.o
 setup-$(CONFIG_X86_VOYAGER) += voyager.o
 
Index: linux-2.6/arch/x86/boot/boot.h
===================================================================
--- linux-2.6.orig/arch/x86/boot/boot.h
+++ linux-2.6/arch/x86/boot/boot.h
@@ -286,6 +286,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);
 
Index: linux-2.6/arch/x86/boot/video-bios.c
===================================================================
--- linux-2.6.orig/arch/x86/boot/video-bios.c
+++ linux-2.6/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;
Index: linux-2.6/arch/x86/boot/video-mode.c
===================================================================
--- /dev/null
+++ linux-2.6/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;
+}
Index: linux-2.6/arch/x86/boot/video-vesa.c
===================================================================
--- linux-2.6.orig/arch/x86/boot/video-vesa.c
+++ linux-2.6/arch/x86/boot/video-vesa.c
@@ -24,7 +24,11 @@ static struct vesa_mode_info vminfo;
 
 __videocard video_vesa;
 
+#ifndef _WAKEUP
 static void vesa_store_mode_params_graphics(void);
+#else /* _WAKEUP */
+static inline void vesa_store_mode_params_graphics(void) {}
+#endif /* _WAKEUP */
 
 static int vesa_probe(void)
 {
@@ -167,6 +171,8 @@ static int vesa_set_mode(struct mode_inf
 }
 
 
+#ifndef _WAKEUP
+
 /* Switch DAC to 8-bit mode */
 static void vesa_dac_set_8bits(void)
 {
@@ -290,6 +296,8 @@ void vesa_store_edid(void)
 #endif /* CONFIG_FIRMWARE_EDID */
 }
 
+#endif /* not _WAKEUP */
+
 __videocard video_vesa =
 {
 	.card_name	= "VESA",
Index: linux-2.6/arch/x86/boot/video-vga.c
===================================================================
--- linux-2.6.orig/arch/x86/boot/video-vga.c
+++ linux-2.6/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;
 		}
Index: linux-2.6/arch/x86/boot/video.c
===================================================================
--- linux-2.6.orig/arch/x86/boot/video.c
+++ linux-2.6/arch/x86/boot/video.c
@@ -18,21 +18,6 @@
 #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];
@@ -486,6 +330,7 @@ void set_video(void)
 		printf("Undefined video mode number: %x\n", mode);
 		mode = ASK_VGA;
 	}
+	boot_params.hdr.vid_mode = mode;
 	vesa_store_edid();
 	store_mode_params();
 
Index: linux-2.6/arch/x86/kernel/acpi/Makefile
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/Makefile
+++ linux-2.6/arch/x86/kernel/acpi/Makefile
@@ -1,7 +1,14 @@
+subdir-				:= realmode
+
 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)/realmode/wakeup.bin
+
+$(obj)/realmode/wakeup.bin: FORCE
+	$(Q)$(MAKE) $(build)=$(obj)/realmode $@
+
Index: linux-2.6/arch/x86/kernel/acpi/realmode/Makefile
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/Makefile
@@ -0,0 +1,58 @@
+#
+# arch/x86/kernel/acpi/realmode/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
+
+CPPFLAGS_wakeup.lds += -P -C
+
+$(obj)/wakeup.elf: $(src)/wakeup.lds $(WAKEUP_OBJS) FORCE
+	$(call if_changed,ld)
+
+OBJCOPYFLAGS_wakeup.bin	:= -O binary
+
+$(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE
+	$(call if_changed,objcopy)
Index: linux-2.6/arch/x86/kernel/acpi/realmode/copy.S
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/copy.S
@@ -0,0 +1 @@
+#include "../../../boot/copy.S"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/video-bios.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/video-bios.c
@@ -0,0 +1 @@
+#include "../../../boot/video-bios.c"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/video-mode.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/video-mode.c
@@ -0,0 +1 @@
+#include "../../../boot/video-mode.c"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/video-vesa.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/video-vesa.c
@@ -0,0 +1 @@
+#include "../../../boot/video-vesa.c"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/video-vga.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/video-vga.c
@@ -0,0 +1 @@
+#include "../../../boot/video-vga.c"
Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakemain.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/wakemain.c
@@ -0,0 +1,26 @@
+#include "wakeup.h"
+#include "boot.h"
+
+extern volatile struct wakeup_header wakeup_header;
+
+void main(void)
+{
+	/* Kill machine if structures are wrong */
+	if (wakeup_header.real_magic != 0x12345678)
+		while(1);
+
+	if (wakeup_header.realmode_flags & 4) {
+		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");
+	}
+
+	if (wakeup_header.realmode_flags & 1) {
+		asm volatile("lcallw   $0xc000,$3");
+//		("movw    %cs, %ax;	movw    %ax, %ds;	movw	%ax, %es; movw    %ax, %ss");
+	}
+
+	if (wakeup_header.realmode_flags & 2) {
+		/* Need to call BIOS */
+		probe_cards(0);
+		set_mode(wakeup_header.video_mode);
+	}
+}
Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
@@ -0,0 +1,113 @@
+/*
+ * ACPI wakeup real mode startup stub
+ */
+#include <asm/segment.h>
+#include <asm/msr-index.h>
+#include <asm/page_64.h>
+#include <asm/pgtable_64.h>
+
+	.code16
+	.section ".header", "a"
+
+/* This should match the structure in wakeup.h */
+		.globl	wakeup_header
+wakeup_header:
+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
+realmode_flags:	.long	0
+real_magic:	.long	0
+trampoline_segment:	.word 0
+signature:	.long	0x51ee1111
+
+	.text
+	.globl	_start
+	.code16
+wakeup_code:
+_start:
+	cli
+	cld
+
+	/* Set up segments */
+	movw	%cs, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %ss
+
+	movl	$wakeup_stack_end, %esp
+
+	/* 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
+
+	/* Call the C code */
+	calll	main
+
+	/* Do any other stuff... */
+
+#ifndef CONFIG_64BIT
+	/* 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
+#else
+	pushw	$0
+	pushw	trampoline_segment
+	pushw	$0
+	lret
+#endif
+
+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:
Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.h
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.h
@@ -0,0 +1,35 @@
+/*
+ * 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
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+
+/* This must match data at wakeup.S */
+struct wakeup_header {
+	u16 video_mode;		/* Video mode number */
+	u16 _jmp1;		/* ljmpl opcode, 32-bit only */
+	u32 pmode_entry;	/* Protected mode resume point, 32-bit only */
+	u16 _jmp2;		/* CS value, 32-bit only */
+	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 realmode_flags;
+	u32 real_magic;
+	u16 trampoline_segment;	/* segment with trampoline code, 64-bit only */
+	u32 signature;		/* To check we have correct structure */
+} __attribute__((__packed__));
+#endif
+
+#define HEADER_OFFSET 0x3f00
+#define WAKEUP_SIZE   0x4000
+
+
+#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
Index: linux-2.6/arch/x86/kernel/acpi/sleep.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c
+++ linux-2.6/arch/x86/kernel/acpi/sleep.c
@@ -11,29 +11,84 @@
 #include <linux/cpumask.h>
 
 #include <asm/smp.h>
+#include "realmode/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 acpi_copy_wakeup_routine(unsigned long);
+extern unsigned long setup_trampoline(void);
+extern void wakeup_long64(void);
+
+extern unsigned long saved_video_mode;
+extern long saved_magic;
+extern volatile unsigned long init_rsp;
+extern void (*initial_code)(void);
+#ifndef CONFIG_64BIT
+extern int wakeup_pmode_return;
+extern char swsusp_pg_dir[PAGE_SIZE];
+#else
+static char temp_stack[10240];
+#endif
+
+extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
 
 /**
  * acpi_save_state_mem - save kernel state
  *
  * 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(KERN_ERR "Could not allocate memory during boot, S3 disabled\n");
+	struct wakeup_header *header;
+
+	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, WAKEUP_SIZE);
+
+	header = (struct wakeup_header *)(acpi_realmode + HEADER_OFFSET);
+	if (header->signature != 0x51ee1111) {
+		printk(KERN_ERR "wakeup header does not match\n");
+		return -EINVAL;
+	}
+
+	header->video_mode = saved_video_mode;
+
+#ifndef CONFIG_64BIT
+	store_gdt(&header->pmode_gdt);
+
+	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);
+	}
+#endif /* !CONFIG_64BIT */
+
+	header->pmode_cr0 = read_cr0();
+	header->pmode_cr4 = read_cr4();
+	header->realmode_flags = acpi_realmode_flags;
+	header->real_magic = 0x12345678;
+
+#ifndef CONFIG_64BIT
+	header->pmode_entry = &wakeup_pmode_return;
+	header->pmode_cr3 = swsusp_pg_dir - __PAGE_OFFSET;
+	saved_magic = 0x12345678;
+#else /* CONFIG_64BIT */
+	header->trampoline_segment = setup_trampoline() >> 4;
+	init_rsp = (unsigned long)temp_stack + 4096;
+	initial_code = wakeup_long64;
+	saved_magic = 0x123456789abcdef0;
+#endif /* CONFIG_64BIT */
 
 	return 0;
 }
@@ -56,15 +111,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) > WAKEUP_SIZE) {
 		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(WAKEUP_SIZE);
+
+	if (!acpi_realmode) {
 		printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");
+		return;
+	}
+
+	acpi_wakeup_address = acpi_realmode;
 }
 
 
Index: linux-2.6/arch/x86/kernel/acpi/wakeup_32.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/wakeup_32.S
+++ linux-2.6/arch/x86/kernel/acpi/wakeup_32.S
@@ -3,178 +3,12 @@
 #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
-
-	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:
-
-	# 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_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
+# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
 
 	.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:
 	movw	$__KERNEL_DS, %ax
 	movw	%ax, %ss
@@ -187,7 +21,7 @@ wakeup_pmode_return:
 	lgdt	saved_gdt
 	lidt	saved_idt
 	lldt	saved_ldt
-	ljmp	$(__KERNEL_CS),$1f
+	ljmp	$(__KERNEL_CS), $1f
 1:
 	movl	%cr3, %eax
 	movl	%eax, %cr3
@@ -201,82 +35,41 @@ wakeup_pmode_return:
 	jne	bogus_magic
 
 	# jump to place where we left off
-	movl	saved_eip,%eax
+	movl	saved_eip, %eax
 	jmp	*%eax
 
 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
-	movl %ebp, saved_context_ebp
-	movl %esi, saved_context_esi
-	movl %edi, saved_context_edi
-	pushfl ; popl saved_context_eflags
+	movl	%ebx, saved_context_ebx
+	movl	%ebp, saved_context_ebp
+	movl	%esi, saved_context_esi
+	movl	%edi, saved_context_edi
+	pushfl
+	popl	saved_context_eflags
 
-	movl $ret_point, saved_eip
+	movl	$ret_point, saved_eip
 	ret
 
 
 restore_registers:
-	movl saved_context_ebp, %ebp
-	movl saved_context_ebx, %ebx
-	movl saved_context_esi, %esi
-	movl saved_context_edi, %edi
-	pushl saved_context_eflags ; popfl
-	ret	
+	movl	saved_context_ebp, %ebp
+	movl	saved_context_ebx, %ebx
+	movl	saved_context_esi, %esi
+	movl	saved_context_edi, %edi
+	pushl	saved_context_eflags
+	popfl
+	ret
 
 ENTRY(do_suspend_lowlevel)
 	call	save_processor_state
Index: linux-2.6/arch/x86/kernel/acpi/wakeup_64.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/wakeup_64.S
+++ linux-2.6/arch/x86/kernel/acpi/wakeup_64.S
@@ -7,191 +7,18 @@
 #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:
-
-	mov	%ds, %ax			# Find 32bit wakeup_code addr
-	movzx   %ax, %esi			# (Convert %ds:gdt to a liner ptr)
-	shll    $4, %esi
-						# Fix up the vectors
-	addl    %esi, wakeup_32_vector - wakeup_code
-	addl    %esi, wakeup_long64_vector - wakeup_code
-	addl    %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
-
-	lidtl	%ds:idt_48a - wakeup_code
-	lgdtl	%ds:gdt_48a - wakeup_code	# load gdt with whatever is
-						# appropriate
-
-	movl	$1, %eax			# protected mode (PE) bit
-	lmsw	%ax				# This is it!
-	jmp	1f
-1:
-
-	ljmpl   *(wakeup_32_vector - wakeup_code)
-
-	.balign 4
-wakeup_32_vector:
-	.long   wakeup_32 - wakeup_code
-	.word   __KERNEL32_CS, 0
-
-	.code32
-wakeup_32:
-# Running in this code, but at low address; paging is not yet turned on.
-
-	movl	$__KERNEL_DS, %eax
-	movl	%eax, %ds
-
-	/*
-	 * Prepare for entering 64bits mode
-	 */
-
-	/* Enable PAE */
-	xorl	%eax, %eax
-	btsl	$5, %eax
-	movl	%eax, %cr4
-
-	/* Setup early boot stage 4 level pagetables */
-	leal    (wakeup_level4_pgt - wakeup_code)(%esi), %eax
-	movl	%eax, %cr3
-
-        /* Check if nx is implemented */
-        movl    $0x80000001, %eax
-        cpuid
-        movl    %edx,%edi
-
-	/* Enable Long Mode */
-	xorl    %eax, %eax
-	btsl	$_EFER_LME, %eax
-
-	/* No Execute supported? */
-	btl	$20,%edi
-	jnc     1f
-	btsl	$_EFER_NX, %eax
-				
-	/* Make changes effective */
-1:	movl    $MSR_EFER, %ecx
-	xorl    %edx, %edx
-	wrmsr
-
-	xorl	%eax, %eax
-	btsl	$31, %eax			/* Enable paging and in turn activate Long Mode */
-	btsl	$0, %eax			/* Enable protected mode */
-
-	/* Make changes effective */
-	movl	%eax, %cr0
-
-	/* At this point:
-		CR4.PAE must be 1
-		CS.L must be 0
-		CR3 must point to PML4
-		Next instruction must be a branch
-		This must be on identity-mapped page
-	*/
-	/*
-	 * At this point we're in long mode but in 32bit compatibility mode
-	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
-	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
-	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
-	 */
-
-	/* Finally jump in 64bit mode */
-        ljmp    *(wakeup_long64_vector - wakeup_code)(%esi)
-
-	.balign 4
-wakeup_long64_vector:
-	.long   wakeup_long64 - wakeup_code
-	.word   __KERNEL_CS, 0
 
 .code64
-
-	/* Hooray, we are in Long 64-bit mode (but still running in
-	 * low memory)
-	 */
-wakeup_long64:
 	/*
-	 * We must switch to a new descriptor in kernel space for the GDT
-	 * because soon the kernel won't have access anymore to the userspace
-	 * addresses where we're currently running on. We have to do that here
-	 * because in 32bit we couldn't load a 64bit linear address.
+	 * Hooray, we are in Long 64-bit mode (but still running in low memory)
 	 */
-	lgdt	cpu_gdt_descr
-
-	movq    saved_magic, %rax
-	movq    $0x123456789abcdef0, %rdx
-	cmpq    %rdx, %rax
-	jne     bogus_64_magic
+ENTRY(wakeup_long64)
+wakeup_long64:
+	movq	saved_magic, %rax
+	movq	$0x123456789abcdef0, %rdx
+	cmpq	%rdx, %rax
+	jne	bogus_64_magic
 
-	nop
-	nop
 	movw	$__KERNEL_DS, %ax
 	movw	%ax, %ss	
 	movw	%ax, %ds
@@ -208,130 +35,8 @@ wakeup_long64:
 	movq	saved_rip, %rax
 	jmp	*%rax
 
-.code32
-
-	.align	64	
-gdta:
-	/* Its good to keep gdt in sync with one in trampoline.S */
-	.word	0, 0, 0, 0			# dummy
-	/* ??? Why I need the accessed bit set in order for this to work? */
-	.quad   0x00cf9b000000ffff              # __KERNEL32_CS
-	.quad   0x00af9b000000ffff              # __KERNEL_CS
-	.quad   0x00cf93000000ffff              # __KERNEL_DS
-
-idt_48a:
-	.word	0				# idt limit = 0
-	.word	0, 0				# idt base = 0L
-
-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
-wakeup_stack:		# Just below end of page
-
-.org   0x1000
-ENTRY(wakeup_level4_pgt)
-	.quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
-	.fill   510,8,0
-	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
-	.quad   level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
-
-ENTRY(wakeup_end)
-	
-##
-# acpi_copy_wakeup_routine
-#
-# Copy the above routine to low memory.
-#
-# Parameters:
-# %rdi:	place to copy wakeup routine to
-#
-# Returned address is location of code in low memory (past data and stack)
-#
-	.code64
-ENTRY(acpi_copy_wakeup_routine)
-	pushq	%rax
-	pushq	%rdx
-
-	movl	saved_video_mode, %edx
-	movl	%edx, video_mode - wakeup_start (,%rdi)
-	movl	acpi_realmode_flags, %edx
-	movl	%edx, realmode_flags - wakeup_start (,%rdi)
-	movq	$0x12345678, real_magic - wakeup_start (,%rdi)
-	movq	$0x123456789abcdef0, %rdx
-	movq	%rdx, saved_magic
-
-	movq    saved_magic, %rax
-	movq    $0x123456789abcdef0, %rdx
-	cmpq    %rdx, %rax
-	jne     bogus_64_magic
-
-	# restore the regs we used
-	popq	%rdx
-	popq	%rax
-ENTRY(do_suspend_lowlevel_s4bios)
-	ret
+	jmp	bogus_64_magic
 
 	.align 2
 	.p2align 4,,15
@@ -414,7 +119,7 @@ do_suspend_lowlevel:
 	jmp	restore_processor_state
 .LFE5:
 .Lfe5:
-	.size	do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel
+	.size	do_suspend_lowlevel, .Lfe5-do_suspend_lowlevel
 	
 .data
 ALIGN
Index: linux-2.6/arch/x86/kernel/acpi/wakeup_rm.S
===================================================================
--- /dev/null
+++ linux-2.6/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/realmode/wakeup.bin"
+wakeup_code_end:
+	.size	wakeup_code_start, .-wakeup_code_start
Index: linux-2.6/arch/x86/kernel/head_64.S
===================================================================
--- linux-2.6.orig/arch/x86/kernel/head_64.S
+++ linux-2.6/arch/x86/kernel/head_64.S
@@ -127,10 +127,6 @@ ident_complete:
 	addq	%rbp, trampoline_level4_pgt + 0(%rip)
 	addq	%rbp, trampoline_level4_pgt + (511*8)(%rip)
 #endif
-#ifdef CONFIG_ACPI_SLEEP
-	addq	%rbp, wakeup_level4_pgt + 0(%rip)
-	addq	%rbp, wakeup_level4_pgt + (511*8)(%rip)
-#endif
 
 	/* Due to ENTRY(), sometimes the empty space gets filled with
 	 * zeros. Better take a jmp than relying on empty space being
Index: linux-2.6/arch/x86/kernel/setup_32.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/setup_32.c
+++ linux-2.6/arch/x86/kernel/setup_32.c
@@ -186,7 +186,7 @@ EXPORT_SYMBOL(ist_info);
 extern void early_cpu_init(void);
 extern int root_mountflags;
 
-unsigned long saved_videomode;
+unsigned long saved_video_mode;
 
 #define RAMDISK_IMAGE_START_MASK	0x07FF
 #define RAMDISK_PROMPT_FLAG		0x8000
@@ -713,7 +713,7 @@ void __init setup_arch(char **cmdline_p)
 	edid_info = boot_params.edid_info;
 	apm_info.bios = boot_params.apm_bios_info;
 	ist_info = boot_params.ist_info;
-	saved_videomode = boot_params.hdr.vid_mode;
+	saved_video_mode = boot_params.hdr.vid_mode;
 	if( boot_params.sys_desc_table.length != 0 ) {
 		set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2);
 		machine_id = boot_params.sys_desc_table.table[0];
Index: linux-2.6/arch/x86/kernel/smpboot_64.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/smpboot_64.c
+++ linux-2.6/arch/x86/kernel/smpboot_64.c
@@ -132,7 +132,7 @@ struct task_struct *idle_thread_array[NR
  * has made sure it's suitably aligned.
  */
 
-static unsigned long __cpuinit setup_trampoline(void)
+unsigned long __cpuinit setup_trampoline(void)
 {
 	void *tramp = __va(SMP_TRAMPOLINE_BASE); 
 	memcpy(tramp, trampoline_data, trampoline_end - trampoline_data);
@@ -649,6 +649,9 @@ do_rest:
 	*((volatile unsigned short *) phys_to_virt(0x467)) = start_rip & 0xf;
 	Dprintk("3.\n");
 
+	/* Trampoline assumes it is at beggining of segment */
+	BUG_ON(start_rip & 0xf);
+
 	/*
 	 * Be paranoid about clearing APIC errors.
 	 */
@@ -656,11 +659,6 @@ do_rest:
 	apic_read(APIC_ESR);
 
 	/*
-	 * Status is now clean
-	 */
-	boot_error = 0;
-
-	/*
 	 * Starting actual IPI sequence...
 	 */
 	boot_error = wakeup_secondary_via_INIT(apicid, start_rip);
Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.lds.S
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.lds.S
@@ -0,0 +1,61 @@
+/*
+ * wakeup.ld
+ *
+ * Linker script for the real-mode wakeup code
+ */
+#undef i386
+#include "wakeup.h"
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = HEADER_OFFSET;
+	.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*)
+	}
+
+	. = ASSERT(_end <= WAKEUP_SIZE, "Wakeup too big!");
+}

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-09  0:18               ` Rafael J. Wysocki
@ 2008-02-09  0:32                 ` H. Peter Anvin
  2008-02-09 13:48                   ` Rafael J. Wysocki
  2008-02-10 21:14                   ` Pavel Machek
  0 siblings, 2 replies; 62+ messages in thread
From: H. Peter Anvin @ 2008-02-09  0:32 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Pavel Machek, kernel list, Linux-pm mailing list, Sam Ravnborg

Rafael J. Wysocki wrote:
> 
> Consolidated patch is appended.  I'll test it tomorrow on x86-64.
> 
> I'd like to add the cleaned up beeping code to it and perhaps try to push it
> for -mm testing without any further changes.  We can still do more cleanups in
> followup patches.
> 

The other thing to figure out is to what extent we can clean up the 
conditionals in the video mode code by refactoring.  All they really do 
here is save space by removing functionality not needed for wakeup, 
because I didn't know how much space was realistic.

It's possible we can remove them altogether by having a dummy 
boot_params structure (4K).

	-hpa

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-09  0:32                 ` H. Peter Anvin
@ 2008-02-09 13:48                   ` Rafael J. Wysocki
  2008-02-10 21:14                   ` Pavel Machek
  1 sibling, 0 replies; 62+ messages in thread
From: Rafael J. Wysocki @ 2008-02-09 13:48 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Pavel Machek, kernel list, Linux-pm mailing list, Sam Ravnborg

On Saturday, 9 of February 2008, H. Peter Anvin wrote:
> Rafael J. Wysocki wrote:
> > 
> > Consolidated patch is appended.  I'll test it tomorrow on x86-64.
> > 
> > I'd like to add the cleaned up beeping code to it and perhaps try to push it
> > for -mm testing without any further changes.  We can still do more cleanups in
> > followup patches.
> > 
> 
> The other thing to figure out is to what extent we can clean up the 
> conditionals in the video mode code by refactoring.  All they really do 
> here is save space by removing functionality not needed for wakeup, 
> because I didn't know how much space was realistic.

OK, I have an idea.

For now, below is a patch that adds your beeping code to wakemain.c (on top of
the previous one). ;-)

Rafael

---
 arch/x86/kernel/acpi/realmode/wakemain.c |   69 ++++++++++++++++++++++++++++---
 1 file changed, 63 insertions(+), 6 deletions(-)

Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakemain.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/acpi/realmode/wakemain.c
+++ linux-2.6/arch/x86/kernel/acpi/realmode/wakemain.c
@@ -3,20 +3,77 @@
 
 extern volatile struct wakeup_header wakeup_header;
 
+static void udelay(int loops)
+{
+	while (loops--)
+		io_delay();	/* Approximately 1 us */
+}
+
+static void beep(unsigned int hz)
+{
+	u8 enable;
+
+	if (!hz) {
+		enable = 0x00;		/* Turn off speaker */
+	} else {
+		u16 div = 1193181/hz;
+
+		outb(0xb6, 0x43);	/* Ctr 2, squarewave, load, binary */
+		io_delay();
+		outb(div, 0x42);	/* LSB of counter */
+		io_delay();
+		outb(div >> 8, 0x42);	/* MSB of counter */
+		io_delay();
+
+		enable = 0x03;		/* Turn on speaker */
+	}
+	inb(0x61);		/* Dummy read of System Control Port B */
+	io_delay();
+	outb(enable, 0x61);	/* Enable timer 2 output to speaker */
+	io_delay();
+}
+
+#define DOT_HZ		880
+#define DASH_HZ		587
+#define US_PER_DOT	125000
+
+/* Okay, this is totally silly, but it's kind of fun. */
+static void send_morse(const char *pattern)
+{
+	char s;
+
+	while ((s = *pattern++)) {
+		switch (s) {
+		case '.':
+			beep(DOT_HZ);
+			udelay(US_PER_DOT);
+			beep(0);
+			udelay(US_PER_DOT);
+			break;
+		case '-':
+			beep(DASH_HZ);
+			udelay(US_PER_DOT * 3);
+			beep(0);
+			udelay(US_PER_DOT);
+			break;
+		default:	/* Assume it's a space */
+			udelay(US_PER_DOT * 3);
+			break;
+		}
+	}
+}
+
 void main(void)
 {
 	/* Kill machine if structures are wrong */
 	if (wakeup_header.real_magic != 0x12345678)
 		while(1);
 
-	if (wakeup_header.realmode_flags & 4) {
-		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");
-	}
+	if (wakeup_header.realmode_flags & 4)
+		send_morse("...-");
 
-	if (wakeup_header.realmode_flags & 1) {
+	if (wakeup_header.realmode_flags & 1)
 		asm volatile("lcallw   $0xc000,$3");
-//		("movw    %cs, %ax;	movw    %ax, %ds;	movw	%ax, %es; movw    %ax, %ss");
-	}
 
 	if (wakeup_header.realmode_flags & 2) {
 		/* Need to call BIOS */

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-09  0:32                 ` H. Peter Anvin
  2008-02-09 13:48                   ` Rafael J. Wysocki
@ 2008-02-10 21:14                   ` Pavel Machek
  2008-02-10 21:21                     ` Sam Ravnborg
  1 sibling, 1 reply; 62+ messages in thread
From: Pavel Machek @ 2008-02-10 21:14 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Rafael J. Wysocki, kernel list, Linux-pm mailing list, Sam Ravnborg

On Fri 2008-02-08 16:32:08, H. Peter Anvin wrote:
> Rafael J. Wysocki wrote:
>>
>> Consolidated patch is appended.  I'll test it tomorrow on x86-64.
>>
>> I'd like to add the cleaned up beeping code to it and perhaps try to push it
>> for -mm testing without any further changes.  We can still do more cleanups in
>> followup patches.
>>
>
> The other thing to figure out is to what extent we can clean up the 
> conditionals in the video mode code by refactoring.  All they really do 
> here is save space by removing functionality not needed for wakeup, because 
> I didn't know how much space was realistic.
>
> It's possible we can remove them altogether by having a dummy boot_params 
> structure (4K).

I'd say that few #ifdefs are acceptable if we save 4K, but...

Sam... is there something that urgently needs fixing?
									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] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-10 21:14                   ` Pavel Machek
@ 2008-02-10 21:21                     ` Sam Ravnborg
  0 siblings, 0 replies; 62+ messages in thread
From: Sam Ravnborg @ 2008-02-10 21:21 UTC (permalink / raw)
  To: Pavel Machek
  Cc: H. Peter Anvin, Rafael J. Wysocki, kernel list, Linux-pm mailing list

On Sun, Feb 10, 2008 at 10:14:57PM +0100, Pavel Machek wrote:
> On Fri 2008-02-08 16:32:08, H. Peter Anvin wrote:
> > Rafael J. Wysocki wrote:
> >>
> >> Consolidated patch is appended.  I'll test it tomorrow on x86-64.
> >>
> >> I'd like to add the cleaned up beeping code to it and perhaps try to push it
> >> for -mm testing without any further changes.  We can still do more cleanups in
> >> followup patches.
> >>
> >
> > The other thing to figure out is to what extent we can clean up the 
> > conditionals in the video mode code by refactoring.  All they really do 
> > here is save space by removing functionality not needed for wakeup, because 
> > I didn't know how much space was realistic.
> >
> > It's possible we can remove them altogether by having a dummy boot_params 
> > structure (4K).
> 
> I'd say that few #ifdefs are acceptable if we save 4K, but...
> 
> Sam... is there something that urgently needs fixing?

I will prepare some build system bits later.
So please use what you have today and I can always clean it up
when I have something better.

So for the bits I have competence in - no issues.

	Sam

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [rft] s2ram wakeup moves to .c, could fix few machines
  2008-02-06  1:51       ` H. Peter Anvin
  2008-02-06  1:56         ` Rafael J. Wysocki
  2008-02-06 11:29         ` Pavel Machek
@ 2008-02-14  2:54         ` Bill Davidsen
  2 siblings, 0 replies; 62+ messages in thread
From: Bill Davidsen @ 2008-02-14  2:54 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Rafael J. Wysocki, Pavel Machek, kernel list, Linux-pm mailing list

H. Peter Anvin wrote:
> Rafael J. Wysocki wrote:
>>> The asm() for making beeps really need to be moved to a function and 
>>> cleaned up (redone in C using inb()/outb()) if they are to be 
>>> retained at all.
>>
>> Yes, they are.  For some people they're the only tool to debug broken 
>> resume.
> 
> That's fine, but they should get cleaned up.
> 
> /me is tempted to provide a version which can send messages in Morse 
> Code ;)
> 
Thought someone did that a while ago. Alan Cox, maybe.

-- 
Bill Davidsen <davidsen@tmr.com>
   "We have more to fear from the bungling of the incompetent than from
the machinations of the wicked."  - from Slashdot

^ permalink raw reply	[flat|nested] 62+ messages in thread

end of thread, other threads:[~2008-02-14  2:54 UTC | newest]

Thread overview: 62+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-05 19:06 [rft] s2ram wakeup moves to .c, could fix few machines Pavel Machek
2008-02-06  1:27 ` Rafael J. Wysocki
2008-02-06  1:36   ` H. Peter Anvin
2008-02-06  1:42     ` Rafael J. Wysocki
2008-02-06  1:51       ` H. Peter Anvin
2008-02-06  1:56         ` Rafael J. Wysocki
2008-02-06 11:29         ` Pavel Machek
2008-02-14  2:54         ` Bill Davidsen
2008-02-06 23:48   ` Rafael J. Wysocki
2008-02-07 22:12     ` Rafael J. Wysocki
2008-02-07 22:28       ` Sam Ravnborg
2008-02-07 22:34         ` H. Peter Anvin
2008-02-08 21:31         ` Pavel Machek
2008-02-08 21:34         ` Pavel Machek
2008-02-08 21:41         ` Pavel Machek
2008-02-08 21:47           ` Sam Ravnborg
2008-02-08 21:49         ` Pavel Machek
2008-02-07 22:28       ` Pavel Machek
2008-02-07 22:40         ` Rafael J. Wysocki
2008-02-07 22:44           ` H. Peter Anvin
2008-02-07 22:53             ` Rafael J. Wysocki
2008-02-07 22:45           ` H. Peter Anvin
2008-02-07 22:49             ` Pavel Machek
2008-02-08 21:13           ` Pavel Machek
2008-02-08 21:41             ` Maxim Levitsky
2008-02-08 21:51               ` Pavel Machek
2008-02-07 22:46         ` H. Peter Anvin
2008-02-07 22:51           ` Pavel Machek
2008-02-07 23:09             ` Rafael J. Wysocki
2008-02-07 22:57           ` Rafael J. Wysocki
2008-02-07 23:14             ` H. Peter Anvin
2008-02-08 21:35               ` Pavel Machek
2008-02-07 22:38       ` H. Peter Anvin
2008-02-07 23:06         ` Rafael J. Wysocki
2008-02-07 23:13           ` H. Peter Anvin
2008-02-07 23:35           ` Pavel Machek
2008-02-07 23:36             ` Rafael J. Wysocki
2008-02-07 23:41               ` Pavel Machek
2008-02-07 23:42             ` H. Peter Anvin
2008-02-08  7:04               ` Pavel Machek
2008-02-08  7:40                 ` H. Peter Anvin
2008-02-08 16:23                 ` Rafael J. Wysocki
2008-02-08 21:00                   ` Pavel Machek
2008-02-08 21:02                     ` H. Peter Anvin
2008-02-08 21:09                       ` Pavel Machek
2008-02-08 21:18                         ` H. Peter Anvin
2008-02-08 21:20                     ` [linux-pm] " Alan Stern
2008-02-08 21:23                       ` Pavel Machek
2008-02-08 21:27                         ` H. Peter Anvin
2008-02-08 21:31                           ` Pavel Machek
2008-02-08 21:56                             ` Rafael J. Wysocki
2008-02-08 21:59                               ` Pavel Machek
2008-02-08 21:56         ` Pavel Machek
2008-02-08 21:58         ` Pavel Machek
2008-02-08 22:01           ` Rafael J. Wysocki
2008-02-08 22:08             ` Pavel Machek
2008-02-09  0:18               ` Rafael J. Wysocki
2008-02-09  0:32                 ` H. Peter Anvin
2008-02-09 13:48                   ` Rafael J. Wysocki
2008-02-10 21:14                   ` Pavel Machek
2008-02-10 21:21                     ` Sam Ravnborg
2008-02-06 23:37 ` 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;
as well as URLs for NNTP newsgroup(s).