95 lines
2.0 KiB
C
95 lines
2.0 KiB
C
/*
|
|
* arch/s390/mm/pgtable.c
|
|
*
|
|
* Copyright IBM Corp. 2007
|
|
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
|
|
*/
|
|
|
|
#include <linux/sched.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/swap.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/pagemap.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/module.h>
|
|
#include <linux/quicklist.h>
|
|
|
|
#include <asm/system.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/pgalloc.h>
|
|
#include <asm/tlb.h>
|
|
#include <asm/tlbflush.h>
|
|
|
|
#ifndef CONFIG_64BIT
|
|
#define ALLOC_ORDER 1
|
|
#else
|
|
#define ALLOC_ORDER 2
|
|
#endif
|
|
|
|
unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
|
|
{
|
|
struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
|
|
|
|
if (!page)
|
|
return NULL;
|
|
page->index = 0;
|
|
if (noexec) {
|
|
struct page *shadow = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
|
|
if (!shadow) {
|
|
__free_pages(page, ALLOC_ORDER);
|
|
return NULL;
|
|
}
|
|
page->index = page_to_phys(shadow);
|
|
}
|
|
return (unsigned long *) page_to_phys(page);
|
|
}
|
|
|
|
void crst_table_free(unsigned long *table)
|
|
{
|
|
unsigned long *shadow = get_shadow_table(table);
|
|
|
|
if (shadow)
|
|
free_pages((unsigned long) shadow, ALLOC_ORDER);
|
|
free_pages((unsigned long) table, ALLOC_ORDER);
|
|
}
|
|
|
|
/*
|
|
* page table entry allocation/free routines.
|
|
*/
|
|
unsigned long *page_table_alloc(int noexec)
|
|
{
|
|
struct page *page = alloc_page(GFP_KERNEL);
|
|
unsigned long *table;
|
|
|
|
if (!page)
|
|
return NULL;
|
|
page->index = 0;
|
|
if (noexec) {
|
|
struct page *shadow = alloc_page(GFP_KERNEL);
|
|
if (!shadow) {
|
|
__free_page(page);
|
|
return NULL;
|
|
}
|
|
table = (unsigned long *) page_to_phys(shadow);
|
|
clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
|
|
page->index = (addr_t) table;
|
|
}
|
|
table = (unsigned long *) page_to_phys(page);
|
|
clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
|
|
return table;
|
|
}
|
|
|
|
void page_table_free(unsigned long *table)
|
|
{
|
|
unsigned long *shadow = get_shadow_pte(table);
|
|
|
|
if (shadow)
|
|
free_page((unsigned long) shadow);
|
|
free_page((unsigned long) table);
|
|
|
|
}
|