-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The first highmem implementation. Signed-off-by: Michal Simek <monstr@monstr.eu>
- Loading branch information
Michal Simek
committed
Mar 23, 2012
1 parent
baab8a8
commit 2f2f371
Showing
6 changed files
with
272 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* | ||
* highmem.h: virtual kernel memory mappings for high memory | ||
* | ||
* Used in CONFIG_HIGHMEM systems for memory pages which | ||
* are not addressable by direct kernel virtual addresses. | ||
* | ||
* Copyright (C) 1999 Gerhard Wichert, Siemens AG | ||
* Gerhard.Wichert@pdb.siemens.de | ||
* | ||
* | ||
* Redesigned the x86 32-bit VM architecture to deal with | ||
* up to 16 Terabyte physical memory. With current x86 CPUs | ||
* we now support up to 64 Gigabytes physical RAM. | ||
* | ||
* Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> | ||
*/ | ||
#ifndef _ASM_HIGHMEM_H | ||
#define _ASM_HIGHMEM_H | ||
|
||
#ifdef __KERNEL__ | ||
|
||
#include <linux/init.h> | ||
#include <linux/interrupt.h> | ||
#include <linux/uaccess.h> | ||
#include <asm/fixmap.h> | ||
|
||
extern pte_t *kmap_pte; | ||
extern pgprot_t kmap_prot; | ||
extern pte_t *pkmap_page_table; | ||
|
||
/* | ||
* Right now we initialize only a single pte table. It can be extended | ||
* easily, subsequent pte tables have to be allocated in one physical | ||
* chunk of RAM. | ||
*/ | ||
/* | ||
* We use one full pte table with 4K pages. And with 16K/64K/256K pages pte | ||
* table covers enough memory (32MB/512MB/2GB resp.), so that both FIXMAP | ||
* and PKMAP can be placed in a single pte table. We use 512 pages for PKMAP | ||
* in case of 16K/64K/256K page sizes. | ||
*/ | ||
|
||
#define PKMAP_ORDER PTE_SHIFT | ||
#define LAST_PKMAP (1 << PKMAP_ORDER) | ||
|
||
#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) \ | ||
& PMD_MASK) | ||
|
||
#define LAST_PKMAP_MASK (LAST_PKMAP - 1) | ||
#define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT) | ||
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) | ||
|
||
extern void *kmap_high(struct page *page); | ||
extern void kunmap_high(struct page *page); | ||
extern void *kmap_atomic_prot(struct page *page, pgprot_t prot); | ||
extern void __kunmap_atomic(void *kvaddr); | ||
|
||
static inline void *kmap(struct page *page) | ||
{ | ||
might_sleep(); | ||
if (!PageHighMem(page)) | ||
return page_address(page); | ||
return kmap_high(page); | ||
} | ||
|
||
static inline void kunmap(struct page *page) | ||
{ | ||
BUG_ON(in_interrupt()); | ||
if (!PageHighMem(page)) | ||
return; | ||
kunmap_high(page); | ||
} | ||
|
||
static inline void *__kmap_atomic(struct page *page) | ||
{ | ||
return kmap_atomic_prot(page, kmap_prot); | ||
} | ||
|
||
static inline struct page *kmap_atomic_to_page(void *ptr) | ||
{ | ||
unsigned long idx, vaddr = (unsigned long) ptr; | ||
pte_t *pte; | ||
|
||
if (vaddr < FIXADDR_START) | ||
return virt_to_page(ptr); | ||
|
||
idx = virt_to_fix(vaddr); | ||
pte = kmap_pte - (idx - FIX_KMAP_BEGIN); | ||
return pte_page(*pte); | ||
} | ||
|
||
#define flush_cache_kmaps() { flush_icache(); flush_dcache(); } | ||
|
||
#endif /* __KERNEL__ */ | ||
|
||
#endif /* _ASM_HIGHMEM_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* highmem.c: virtual kernel memory mappings for high memory | ||
* | ||
* PowerPC version, stolen from the i386 version. | ||
* | ||
* Used in CONFIG_HIGHMEM systems for memory pages which | ||
* are not addressable by direct kernel virtual addresses. | ||
* | ||
* Copyright (C) 1999 Gerhard Wichert, Siemens AG | ||
* Gerhard.Wichert@pdb.siemens.de | ||
* | ||
* | ||
* Redesigned the x86 32-bit VM architecture to deal with | ||
* up to 16 Terrabyte physical memory. With current x86 CPUs | ||
* we now support up to 64 Gigabytes physical RAM. | ||
* | ||
* Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> | ||
* | ||
* Reworked for PowerPC by various contributors. Moved from | ||
* highmem.h by Benjamin Herrenschmidt (c) 2009 IBM Corp. | ||
*/ | ||
|
||
#include <linux/highmem.h> | ||
#include <linux/module.h> | ||
|
||
/* | ||
* The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap | ||
* gives a more generic (and caching) interface. But kmap_atomic can | ||
* be used in IRQ contexts, so in some (very limited) cases we need | ||
* it. | ||
*/ | ||
#include <asm/tlbflush.h> | ||
|
||
void *kmap_atomic_prot(struct page *page, pgprot_t prot) | ||
{ | ||
|
||
unsigned long vaddr; | ||
int idx, type; | ||
|
||
/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ | ||
pagefault_disable(); | ||
if (!PageHighMem(page)) | ||
return page_address(page); | ||
|
||
|
||
type = kmap_atomic_idx_push(); | ||
idx = type + KM_TYPE_NR*smp_processor_id(); | ||
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); | ||
#ifdef CONFIG_DEBUG_HIGHMEM | ||
BUG_ON(!pte_none(*(kmap_pte-idx))); | ||
#endif | ||
set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); | ||
local_flush_tlb_page(NULL, vaddr); | ||
|
||
return (void *) vaddr; | ||
} | ||
EXPORT_SYMBOL(kmap_atomic_prot); | ||
|
||
void __kunmap_atomic(void *kvaddr) | ||
{ | ||
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; | ||
int type; | ||
|
||
if (vaddr < __fix_to_virt(FIX_KMAP_END)) { | ||
pagefault_enable(); | ||
return; | ||
} | ||
|
||
type = kmap_atomic_idx(); | ||
#ifdef CONFIG_DEBUG_HIGHMEM | ||
{ | ||
unsigned int idx; | ||
|
||
idx = type + KM_TYPE_NR * smp_processor_id(); | ||
BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); | ||
|
||
/* | ||
* force other mappings to Oops if they'll try to access | ||
* this pte without first remap it | ||
*/ | ||
pte_clear(&init_mm, vaddr, kmap_pte-idx); | ||
local_flush_tlb_page(NULL, vaddr); | ||
} | ||
#endif | ||
kmap_atomic_idx_pop(); | ||
pagefault_enable(); | ||
} | ||
EXPORT_SYMBOL(__kunmap_atomic); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters