Commit 8bbde7ed authored by Pavel Machek's avatar Pavel Machek Committed by Linus Torvalds

[PATCH] s3 sleep: make it work when kernel is big

When kernel becomes too big, table allocated in acpi.c is no longer
big enough and machine crashes during acpi_wakeup.S... This fixes
it and adds safety check for acpi_wakeup's code size.
parent 8ae8fc30
...@@ -446,72 +446,19 @@ acpi_boot_init ( ...@@ -446,72 +446,19 @@ acpi_boot_init (
#ifdef CONFIG_ACPI_SLEEP #ifdef CONFIG_ACPI_SLEEP
#define DEBUG
#ifdef DEBUG
#include <linux/serial.h>
#endif
/* address in low memory of the wakeup routine. */ /* address in low memory of the wakeup routine. */
unsigned long acpi_wakeup_address = 0; unsigned long acpi_wakeup_address = 0;
/* new page directory that we will be using */
static pmd_t *pmd;
/* saved page directory */
static pmd_t saved_pmd;
/* page which we'll use for the new page directory */
static pte_t *ptep;
extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
/* static void init_low_mapping(pgd_t *pgd, int pgd_ofs, int pgd_limit)
* acpi_create_identity_pmd
*
* Create a new, identity mapped pmd.
*
* Do this by creating new page directory, and marking all the pages as R/W
* Then set it as the new Page Middle Directory.
* And, of course, flush the TLB so it takes effect.
*
* We save the address of the old one, for later restoration.
*/
static void acpi_create_identity_pmd (void)
{ {
pgd_t *pgd; int pgd_ofs = 0;
int i;
ptep = (pte_t*)__get_free_page(GFP_KERNEL);
/* fill page with low mapping */
for (i = 0; i < PTRS_PER_PTE; i++)
set_pte(ptep + i, pfn_pte(i, PAGE_SHARED));
pgd = pgd_offset(current->active_mm, 0); while ((pgd_ofs < pgd_limit) && (pgd_ofs + USER_PTRS_PER_PGD < PTRS_PER_PGD)) {
pmd = pmd_alloc(current->mm,pgd, 0); set_pgd(pgd, *(pgd+USER_PTRS_PER_PGD));
pgd_ofs++, pgd++;
/* save the old pmd */ }
saved_pmd = *pmd;
/* set the new one */
set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(ptep)));
/* flush the TLB */
local_flush_tlb();
}
/*
* acpi_restore_pmd
*
* Restore the old pmd saved by acpi_create_identity_pmd and
* free the page that said function alloc'd
*/
static void acpi_restore_pmd (void)
{
set_pmd(pmd, saved_pmd);
local_flush_tlb();
free_page((unsigned long)ptep);
} }
/** /**
...@@ -522,7 +469,11 @@ static void acpi_restore_pmd (void) ...@@ -522,7 +469,11 @@ static void acpi_restore_pmd (void)
*/ */
int acpi_save_state_mem (void) int acpi_save_state_mem (void)
{ {
acpi_create_identity_pmd(); #if CONFIG_X86_PAE
panic("S3 and PAE do not like each other for now.");
return 1;
#endif
init_low_mapping(swapper_pg_dir, 0, USER_PTRS_PER_PGD);
acpi_copy_wakeup_routine(acpi_wakeup_address); acpi_copy_wakeup_routine(acpi_wakeup_address);
return 0; return 0;
...@@ -542,7 +493,7 @@ int acpi_save_state_disk (void) ...@@ -542,7 +493,7 @@ int acpi_save_state_disk (void)
*/ */
void acpi_restore_state_mem (void) void acpi_restore_state_mem (void)
{ {
acpi_restore_pmd(); zap_low_mappings();
} }
/** /**
...@@ -555,7 +506,10 @@ void acpi_restore_state_mem (void) ...@@ -555,7 +506,10 @@ void acpi_restore_state_mem (void)
*/ */
void __init acpi_reserve_bootmem(void) void __init acpi_reserve_bootmem(void)
{ {
extern char wakeup_start, wakeup_end;
acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE);
if ((&wakeup_end - &wakeup_start) > PAGE_SIZE)
printk(KERN_CRIT "ACPI: Wakeup code way too big, will crash on attempt to suspend\n");
printk(KERN_DEBUG "ACPI: have wakeup address 0x%8.8lx\n", acpi_wakeup_address); printk(KERN_DEBUG "ACPI: have wakeup address 0x%8.8lx\n", acpi_wakeup_address);
} }
......
...@@ -299,7 +299,7 @@ static void __init pagetable_init (void) ...@@ -299,7 +299,7 @@ static void __init pagetable_init (void)
#endif #endif
} }
void __init zap_low_mappings (void) void zap_low_mappings (void)
{ {
int i; int i;
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment