Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 9769
b: refs/heads/master
c: 3dd0832
h: refs/heads/master
i:
  9767: d318afb
v: v3
  • Loading branch information
Rafael J. Wysocki authored and Linus Torvalds committed Oct 10, 2005
1 parent 29b4a37 commit 2757ed3
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 10 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 52a2d3e45e06012a662f627177729d3196ba8903
refs/heads/master: 3dd083255ddcfa87751fa8e32f61a9547a15a541
127 changes: 127 additions & 0 deletions trunk/arch/x86_64/kernel/suspend.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <linux/smp.h>
#include <linux/suspend.h>
#include <asm/proto.h>
#include <asm/page.h>
#include <asm/pgtable.h>

struct saved_context saved_context;

Expand Down Expand Up @@ -140,4 +142,129 @@ void fix_processor_context(void)

}

#ifdef CONFIG_SOFTWARE_SUSPEND
/* Defined in arch/x86_64/kernel/suspend_asm.S */
extern int restore_image(void);

pgd_t *temp_level4_pgt;

static void **pages;

static inline void *__add_page(void)
{
void **c;

c = (void **)get_usable_page(GFP_ATOMIC);
if (c) {
*c = pages;
pages = c;
}
return c;
}

static inline void *__next_page(void)
{
void **c;

c = pages;
if (c) {
pages = *c;
*c = NULL;
}
return c;
}

/*
* Try to allocate as many usable pages as needed and daisy chain them.
* If one allocation fails, free the pages allocated so far
*/
static int alloc_usable_pages(unsigned long n)
{
void *p;

pages = NULL;
do
if (!__add_page())
break;
while (--n);
if (n) {
p = __next_page();
while (p) {
free_page((unsigned long)p);
p = __next_page();
}
return -ENOMEM;
}
return 0;
}

static void res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end)
{
long i, j;

i = pud_index(address);
pud = pud + i;
for (; i < PTRS_PER_PUD; pud++, i++) {
unsigned long paddr;
pmd_t *pmd;

paddr = address + i*PUD_SIZE;
if (paddr >= end)
break;

pmd = (pmd_t *)__next_page();
set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
for (j = 0; j < PTRS_PER_PMD; pmd++, j++, paddr += PMD_SIZE) {
unsigned long pe;

if (paddr >= end)
break;
pe = _PAGE_NX | _PAGE_PSE | _KERNPG_TABLE | paddr;
pe &= __supported_pte_mask;
set_pmd(pmd, __pmd(pe));
}
}
}

static void set_up_temporary_mappings(void)
{
unsigned long start, end, next;

temp_level4_pgt = (pgd_t *)__next_page();

/* It is safe to reuse the original kernel mapping */
set_pgd(temp_level4_pgt + pgd_index(__START_KERNEL_map),
init_level4_pgt[pgd_index(__START_KERNEL_map)]);

/* Set up the direct mapping from scratch */
start = (unsigned long)pfn_to_kaddr(0);
end = (unsigned long)pfn_to_kaddr(end_pfn);

for (; start < end; start = next) {
pud_t *pud = (pud_t *)__next_page();
next = start + PGDIR_SIZE;
if (next > end)
next = end;
res_phys_pud_init(pud, __pa(start), __pa(next));
set_pgd(temp_level4_pgt + pgd_index(start),
mk_kernel_pgd(__pa(pud)));
}
}

int swsusp_arch_resume(void)
{
unsigned long n;

n = ((end_pfn << PAGE_SHIFT) + PUD_SIZE - 1) >> PUD_SHIFT;
n += (n + PTRS_PER_PUD - 1) / PTRS_PER_PUD + 1;
pr_debug("swsusp_arch_resume(): pages needed = %lu\n", n);
if (alloc_usable_pages(n)) {
free_eaten_memory();
return -ENOMEM;
}
/* We have got enough memory and from now on we cannot recover */
set_up_temporary_mappings();
restore_image();
return 0;
}
#endif /* CONFIG_SOFTWARE_SUSPEND */
17 changes: 11 additions & 6 deletions trunk/arch/x86_64/kernel/suspend_asm.S
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ ENTRY(swsusp_arch_suspend)
call swsusp_save
ret

ENTRY(swsusp_arch_resume)
/* set up cr3 */
leaq init_level4_pgt(%rip),%rax
subq $__START_KERNEL_map,%rax
movq %rax,%cr3

ENTRY(restore_image)
/* switch to temporary page tables */
movq $__PAGE_OFFSET, %rdx
movq temp_level4_pgt(%rip), %rax
subq %rdx, %rax
movq %rax, %cr3
/* Flush TLB */
movq mmu_cr4_features(%rip), %rax
movq %rax, %rdx
andq $~(1<<7), %rdx # PGE
Expand All @@ -69,6 +70,10 @@ loop:
movq pbe_next(%rdx), %rdx
jmp loop
done:
/* go back to the original page tables */
leaq init_level4_pgt(%rip), %rax
subq $__START_KERNEL_map, %rax
movq %rax, %cr3
/* Flush TLB, including "global" things (vmalloc) */
movq mmu_cr4_features(%rip), %rax
movq %rax, %rdx
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/suspend.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,7 @@ void restore_processor_state(void);
struct saved_context;
void __save_processor_state(struct saved_context *ctxt);
void __restore_processor_state(struct saved_context *ctxt);
extern unsigned long get_usable_page(unsigned gfp_mask);
extern void free_eaten_memory(void);

#endif /* _LINUX_SWSUSP_H */
7 changes: 4 additions & 3 deletions trunk/kernel/power/swsusp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ static inline void eat_page(void *page)
*eaten_memory = c;
}

static unsigned long get_usable_page(unsigned gfp_mask)
unsigned long get_usable_page(unsigned gfp_mask)
{
unsigned long m;

Expand All @@ -1109,7 +1109,7 @@ static unsigned long get_usable_page(unsigned gfp_mask)
return m;
}

static void free_eaten_memory(void)
void free_eaten_memory(void)
{
unsigned long m;
void **c;
Expand Down Expand Up @@ -1481,11 +1481,12 @@ static int read_suspend_image(void)
/* Allocate memory for the image and read the data from swap */

error = check_pagedir(pagedir_nosave);
free_eaten_memory();

if (!error)
error = data_read(pagedir_nosave);

if (error) { /* We fail cleanly */
free_eaten_memory();
for_each_pbe (p, pagedir_nosave)
if (p->address) {
free_page(p->address);
Expand Down

0 comments on commit 2757ed3

Please sign in to comment.