From: "H. Peter Anvin" <hpa@zytor.com>
To: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Pavel Machek <pavel@ucw.cz>,
kernel list <linux-kernel@vger.kernel.org>,
Linux-pm mailing list <linux-pm@lists.osdl.org>
Subject: Re: [rft] s2ram wakeup moves to .c, could fix few machines
Date: Thu, 07 Feb 2008 14:38:54 -0800 [thread overview]
Message-ID: <47AB887E.7010000@zytor.com> (raw)
In-Reply-To: <200802072312.31430.rjw@sisk.pl>
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
next prev parent reply other threads:[~2008-02-07 22:38 UTC|newest]
Thread overview: 66+ messages / expand[flat|nested] mbox.gz Atom feed top
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-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: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-07 23:14 ` H. Peter Anvin
2008-02-08 21:35 ` Pavel Machek
2008-02-07 22:38 ` H. Peter Anvin [this message]
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: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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=47AB887E.7010000@zytor.com \
--to=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@lists.osdl.org \
--cc=pavel@ucw.cz \
--cc=rjw@sisk.pl \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.