summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/um/config.in1
-rw-r--r--arch/um/include/mem_user.h8
-rw-r--r--arch/um/include/user_util.h1
-rw-r--r--arch/um/kernel/mem.c236
-rw-r--r--arch/um/kernel/mem_user.c4
-rw-r--r--arch/um/kernel/process_kern.c2
-rw-r--r--arch/um/kernel/tlb.c5
-rw-r--r--arch/um/kernel/um_arch.c29
-rw-r--r--include/asm-um/fixmap.h89
-rw-r--r--include/asm-um/highmem.h6
-rw-r--r--include/asm-um/pgalloc.h1
-rw-r--r--include/asm-um/pgtable.h12
-rw-r--r--include/asm-um/tlbflush.h1
13 files changed, 322 insertions, 73 deletions
diff --git a/arch/um/config.in b/arch/um/config.in
index fe6a5283cfcb..32cac03d468f 100644
--- a/arch/um/config.in
+++ b/arch/um/config.in
@@ -32,6 +32,7 @@ bool 'Symmetric multi-processing support' CONFIG_UML_SMP
define_bool CONFIG_SMP $CONFIG_UML_SMP
int 'Nesting level' CONFIG_NEST_LEVEL 0
int 'Kernel address space size (in .5G units)' CONFIG_KERNEL_HALF_GIGS 1
+bool 'Highmem support' CONFIG_HIGHMEM
endmenu
mainmenu_option next_comment
diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h
index e3177ae21f9a..d26014dc6d18 100644
--- a/arch/um/include/mem_user.h
+++ b/arch/um/include/mem_user.h
@@ -51,8 +51,8 @@ extern unsigned long task_size;
extern int init_mem_user(void);
extern int create_mem_file(unsigned long len);
extern void setup_range(int fd, char *driver, unsigned long start,
- unsigned long total, struct mem_region *region,
- void *reserved);
+ unsigned long total, int need_vm,
+ struct mem_region *region, void *reserved);
extern void map(unsigned long virt, unsigned long p, unsigned long len,
int r, int w, int x);
extern int unmap(void *addr, int len);
@@ -62,8 +62,8 @@ extern void setup_memory(void *entry);
extern unsigned long find_iomem(char *driver, unsigned long *len_out);
extern int init_maps(struct mem_region *region);
extern int nregions(void);
-extern void setup_one_range(int n, int fd, char *driver, unsigned long start,
- unsigned long len, struct mem_region *region);
+extern void init_range(int n, int fd, char *driver, unsigned long start,
+ unsigned long len, struct mem_region *region);
extern int reserve_vm(unsigned long start, unsigned long end, void *e);
extern unsigned long get_vm(unsigned long len);
extern void setup_physmem(unsigned long start, unsigned long usable,
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
index 1aa4b5bb7f56..3a93b60baae3 100644
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -27,6 +27,7 @@ extern unsigned long uml_physmem;
extern unsigned long uml_reserved;
extern unsigned long end_vm;
extern unsigned long start_vm;
+extern unsigned long highmem;
extern int tracing_pid;
extern int honeypot;
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 578c96fb9894..7b6187f762a5 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -27,13 +27,13 @@
#include "init.h"
unsigned long high_physmem;
-
unsigned long low_physmem;
unsigned long vm_start;
-
unsigned long vm_end;
+unsigned long highmem;
+
pgd_t swapper_pg_dir[1024];
unsigned long *empty_zero_page = NULL;
@@ -71,6 +71,9 @@ void mem_init(void)
{
unsigned long start;
+#ifdef CONFIG_HIGHMEM
+ highmem_start_page = phys_page(__pa(high_physmem));
+#endif
max_mapnr = num_physpages = max_low_pfn;
/* clear the zero-page */
@@ -93,16 +96,168 @@ void mem_init(void)
}
/* this will put all low memory onto the freelists */
- totalram_pages += free_all_bootmem();
+ totalram_pages = free_all_bootmem();
+ totalram_pages += highmem >> PAGE_SHIFT;
printk(KERN_INFO "Memory: %luk available\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
kmalloc_ok = 1;
}
+#if CONFIG_HIGHMEM
+pte_t *kmap_pte;
+pgprot_t kmap_prot;
+
+#define kmap_get_fixmap_pte(vaddr) \
+ pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
+
+void __init kmap_init(void)
+{
+ unsigned long kmap_vstart;
+
+ /* cache the first kmap pte */
+ kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+ kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
+
+ kmap_prot = PAGE_KERNEL;
+}
+#endif /* CONFIG_HIGHMEM */
+
+static void __init fixrange_init(unsigned long start, unsigned long end,
+ pgd_t *pgd_base)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ int i, j;
+ unsigned long vaddr;
+
+ vaddr = start;
+ i = __pgd_offset(vaddr);
+ j = __pmd_offset(vaddr);
+ pgd = pgd_base + i;
+
+ for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
+ pmd = (pmd_t *)pgd;
+ for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
+ if (pmd_none(*pmd)) {
+ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+ set_pmd(pmd, __pmd(_KERNPG_TABLE +
+ (unsigned long) pte));
+ if (pte != pte_offset(pmd, 0))
+ BUG();
+ }
+ vaddr += PMD_SIZE;
+ }
+ j = 0;
+ }
+}
+
+int init_maps(struct mem_region *region)
+{
+ struct page *p, *map;
+ int i, n, len;
+
+ if(region == &physmem_region){
+ region->mem_map = mem_map;
+ return(0);
+ }
+ else if(region->mem_map != NULL) return(0);
+
+ n = region->len >> PAGE_SHIFT;
+ len = n * sizeof(struct page);
+ if(kmalloc_ok){
+ map = kmalloc(len, GFP_KERNEL);
+ if(map == NULL) map = vmalloc(len);
+ }
+ else map = alloc_bootmem_low_pages(len);
+
+ if(map == NULL)
+ return(-ENOMEM);
+ for(i = 0; i < n; i++){
+ p = &map[i];
+ set_page_count(p, 0);
+ SetPageReserved(p);
+ INIT_LIST_HEAD(&p->list);
+ }
+ region->mem_map = map;
+ return(0);
+}
+
+static int setup_one_range(int fd, char *driver, unsigned long start, int len,
+ struct mem_region *region)
+{
+ int i;
+
+ for(i = 0; i < NREGIONS; i++){
+ if(regions[i] == NULL) break;
+ }
+ if(i == NREGIONS){
+ printk("setup_range : no free regions\n");
+ return(-1);
+ }
+ init_range(i, fd, driver, start, len, region);
+ return(i);
+}
+
+#ifdef CONFIG_HIGHMEM
+static void init_highmem(void)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long vaddr;
+
+ /*
+ * Permanent kmaps:
+ */
+ vaddr = PKMAP_BASE;
+ fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir);
+
+ pgd = swapper_pg_dir + __pgd_offset(vaddr);
+ pmd = pmd_offset(pgd, vaddr);
+ pte = pte_offset(pmd, vaddr);
+ pkmap_page_table = pte;
+
+ kmap_init();
+}
+
+void setup_highmem(unsigned long len)
+{
+ struct mem_region *region;
+ struct page *page, *map;
+ unsigned long phys;
+ int i, cur, index;
+
+ phys = physmem_size;
+ do {
+ cur = min(len, (unsigned long) REGION_SIZE);
+ i = setup_one_range(-1, NULL, -1, cur, NULL);
+ if(i == -1){
+ printk("setup_highmem - setup_one_range failed\n");
+ return;
+ }
+ region = regions[i];
+ index = phys / PAGE_SIZE;
+ region->mem_map = &mem_map[index];
+
+ map = region->mem_map;
+ for(i = 0; i < (cur >> PAGE_SHIFT); i++){
+ page = &map[i];
+ ClearPageReserved(page);
+ set_bit(PG_highmem, &page->flags);
+ atomic_set(&page->count, 1);
+ __free_page(page);
+ }
+ phys += cur;
+ len -= cur;
+ } while(len > 0);
+}
+#endif
+
void paging_init(void)
{
struct mem_region *region;
- unsigned long zones_size[MAX_NR_ZONES], start, end;
+ unsigned long zones_size[MAX_NR_ZONES], start, end, vaddr;
int i, index;
empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
@@ -111,6 +266,7 @@ void paging_init(void)
zones_size[i] = 0;
zones_size[0] = (high_physmem >> PAGE_SHIFT) -
(uml_physmem >> PAGE_SHIFT);
+ zones_size[2] = highmem >> PAGE_SHIFT;
free_area_init(zones_size);
start = phys_region_index(__pa(uml_physmem));
end = phys_region_index(__pa(high_physmem - 1));
@@ -120,6 +276,18 @@ void paging_init(void)
region->mem_map = &mem_map[index];
if(i > start) free_bootmem(__pa(region->start), region->len);
}
+
+ /*
+ * Fixed mappings, only the page table structure has to be
+ * created - mappings will be set by set_fixmap():
+ */
+ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
+ fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
+
+#if CONFIG_HIGHMEM
+ init_highmem();
+ setup_highmem(highmem);
+#endif
}
pte_t __bad_page(void)
@@ -220,6 +388,8 @@ struct page *arch_validate(struct page *page, int mask, int order)
again:
if(page == NULL) return(page);
+ if(PageHighMem(page)) return(page);
+
addr = (unsigned long) page_address(page);
for(i = 0; i < (1 << order); i++){
current->thread.fault_addr = (void *) addr;
@@ -315,56 +485,22 @@ int nregions(void)
return(NREGIONS);
}
-int init_maps(struct mem_region *region)
-{
- struct page *p, *map;
- int i, n;
-
- if(region == &physmem_region){
- region->mem_map = mem_map;
- return(0);
- }
- else if(region->mem_map != NULL) return(0);
-
- n = region->len >> PAGE_SHIFT;
- map = kmalloc(n * sizeof(struct page), GFP_KERNEL);
- if(map == NULL) map = vmalloc(n * sizeof(struct page));
- if(map == NULL)
- return(-ENOMEM);
- for(i = 0; i < n; i++){
- p = &map[i];
- set_page_count(p, 0);
- SetPageReserved(p);
- INIT_LIST_HEAD(&p->list);
- }
- region->mem_map = map;
- return(0);
-}
-
-void setup_range(int fd, char *driver, unsigned long start,
- unsigned long len, struct mem_region *region, void *reserved)
+void setup_range(int fd, char *driver, unsigned long start, unsigned long len,
+ int need_vm, struct mem_region *region, void *reserved)
{
- int i, incr;
+ int i, cur;
- i = 0;
do {
- for(; i < NREGIONS; i++){
- if(regions[i] == NULL) break;
- }
- if(i == NREGIONS){
- printk("setup_range : no free regions\n");
- return;
- }
- setup_one_range(i, fd, driver, start, len, region);
+ cur = min(len, (unsigned long) REGION_SIZE);
+ i = setup_one_range(fd, driver, start, cur, region);
region = regions[i];
- if(setup_region(region, reserved)){
+ if(need_vm && setup_region(region, reserved)){
kfree(region);
regions[i] = NULL;
return;
}
- incr = min(len, (unsigned long) REGION_SIZE);
- start += incr;
- len -= incr;
+ start += cur;
+ len -= cur;
} while(len > 0);
}
@@ -399,7 +535,7 @@ int setup_iomem(void)
for(i = 0; i < num_iomem_regions; i++){
iomem = &iomem_regions[i];
- setup_range(iomem->fd, iomem->name, -1, iomem->size, NULL,
+ setup_range(iomem->fd, iomem->name, -1, iomem->size, 1, NULL,
NULL);
}
return(0);
@@ -430,7 +566,7 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
if((region == NULL) || (reserved == NULL))
panic("Couldn't allocate physmem region or vm "
"reservation\n");
- setup_range(-1, NULL, start, cur, region, reserved);
+ setup_range(-1, NULL, start, cur, 1, region, reserved);
if(do_free){
unsigned long reserve = reserve_end - start;
@@ -535,7 +671,7 @@ struct page *phys_to_page(unsigned long phys)
return(mem_map + (phys_offset(phys) >> PAGE_SHIFT));
}
-int setup_mem_maps(void)
+static int setup_mem_maps(void)
{
struct mem_region *region;
int i;
diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
index 38069704cf53..abf8b6403cab 100644
--- a/arch/um/kernel/mem_user.c
+++ b/arch/um/kernel/mem_user.c
@@ -77,8 +77,8 @@ int create_mem_file(unsigned long len)
return(fd);
}
-void setup_one_range(int n, int fd, char *driver, unsigned long start,
- unsigned long len, struct mem_region *region)
+void init_range(int n, int fd, char *driver, unsigned long start,
+ unsigned long len, struct mem_region *region)
{
if(fd == -1)
fd = create_mem_file(len);
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index 6ee5bb0e971d..84b788bc3baa 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -528,7 +528,7 @@ unsigned long um_virt_to_phys(void *t, unsigned long addr)
char *current_cmd(void)
{
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
return("(Unknown)");
#else
unsigned long addr = um_virt_to_phys(current, current->mm->arg_start);
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 2edf3ba881c5..2a094df52641 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -178,6 +178,11 @@ void flush_tlb_kernel_vm(void)
flush_tlb_kernel_range(start_vm, end_vm);
}
+void __flush_tlb_one(unsigned long addr)
+{
+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+}
+
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 6546de92fa44..5452d3f2563c 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -4,6 +4,7 @@
*/
#include "linux/config.h"
+#include "linux/kernel.h"
#include "linux/sched.h"
#include "linux/notifier.h"
#include "linux/mm.h"
@@ -109,8 +110,6 @@ static int start_kernel_proc(void *unused)
return(0);
}
-extern unsigned long high_physmem;
-
#ifdef CONFIG_HOST_2G_2G
#define TOP 0x80000000
#else
@@ -160,7 +159,7 @@ void set_cmdline(char *cmd)
snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), " [%s]", cmd);
memset(argv1_begin + strlen(argv1_begin), '\0',
- argv1_end - argv1_begin - strlen(argv1_begin));
+ argv1_end - argv1_begin - strlen(argv1_begin));
}
static char *usage_string =
@@ -263,10 +262,12 @@ unsigned long brk_start;
static struct vm_reserved kernel_vm_reserved;
+#define MIN_VMALLOC (32 * 1024 * 1024)
+
int linux_main(int argc, char **argv)
{
unsigned long avail;
- unsigned long virtmem_size;
+ unsigned long virtmem_size, max_physmem;
unsigned int i, add, err;
void *sp;
@@ -278,7 +279,7 @@ int linux_main(int argc, char **argv)
}
if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
- if(!jail)
+ if(!jail || debug)
remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext), 1);
remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata), 1);
brk_start = (unsigned long) sbrk(0);
@@ -295,20 +296,20 @@ int linux_main(int argc, char **argv)
argv1_end = &argv[1][strlen(argv[1])];
set_usable_vm(uml_physmem, get_kmem_end());
+
+ highmem = 0;
+ max_physmem = get_kmem_end() - uml_physmem - MIN_VMALLOC;
+ if(physmem_size > max_physmem){
+ highmem = physmem_size - max_physmem;
+ physmem_size -= highmem;
+ }
+
high_physmem = uml_physmem + physmem_size;
high_memory = (void *) high_physmem;
- setup_physmem(uml_physmem, uml_reserved, physmem_size);
-
- /* Kernel vm starts after physical memory and is either the size
- * of physical memory or the remaining space left in the kernel
- * area of the address space, whichever is smaller.
- */
start_vm = VMALLOC_START;
- if(start_vm >= get_kmem_end())
- panic("Physical memory too large to allow any kernel "
- "virtual memory");
+ setup_physmem(uml_physmem, uml_reserved, physmem_size);
virtmem_size = physmem_size;
avail = get_kmem_end() - start_vm;
if(physmem_size > avail) virtmem_size = avail;
diff --git a/include/asm-um/fixmap.h b/include/asm-um/fixmap.h
new file mode 100644
index 000000000000..6ae492a9e52e
--- /dev/null
+++ b/include/asm-um/fixmap.h
@@ -0,0 +1,89 @@
+#ifndef __UM_FIXMAP_H
+#define __UM_FIXMAP_H
+
+#include <linux/config.h>
+#include <asm/kmap_types.h>
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special addresses
+ * from the end of virtual memory (0xfffff000) backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * highger than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ */
+
+/*
+ * on UP currently we will have no trace of the fixmap mechanizm,
+ * no page table allocations, etc. This might change in the
+ * future, say framebuffers for the console driver(s) could be
+ * fix-mapped?
+ */
+enum fixed_addresses {
+#ifdef CONFIG_HIGHMEM
+ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
+ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+#endif
+ __end_of_fixed_addresses
+};
+
+extern void __set_fixmap (enum fixed_addresses idx,
+ unsigned long phys, pgprot_t flags);
+
+#define set_fixmap(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+/*
+ * used by vmalloc.c.
+ *
+ * Leave one empty page between vmalloc'ed areas and
+ * the start of the fixmap, and leave one page empty
+ * at the top of mem..
+ */
+extern unsigned long get_kmem_end(void);
+
+#define FIXADDR_TOP (get_kmem_end() - 0x2000)
+#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
+
+#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without tranlation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static inline unsigned long fix_to_virt(const unsigned int idx)
+{
+ /*
+ * this branch gets completely eliminated after inlining,
+ * except when someone tries to use fixaddr indices in an
+ * illegal way. (such as mixing up address types or using
+ * out-of-range indices).
+ *
+ * If it doesn't get removed, the linker will complain
+ * loudly with a reasonably clear error message..
+ */
+ if (idx >= __end_of_fixed_addresses)
+ __this_fixmap_does_not_exist();
+
+ return __fix_to_virt(idx);
+}
+
+#endif
diff --git a/include/asm-um/highmem.h b/include/asm-um/highmem.h
index 6713fb2a4896..36974cb8abc7 100644
--- a/include/asm-um/highmem.h
+++ b/include/asm-um/highmem.h
@@ -1,6 +1,12 @@
#ifndef __UM_HIGHMEM_H
#define __UM_HIGHMEM_H
+#include "asm/page.h"
+#include "asm/fixmap.h"
#include "asm/arch/highmem.h"
+#undef PKMAP_BASE
+
+#define PKMAP_BASE ((FIXADDR_START - LAST_PKMAP * PAGE_SIZE) & PMD_MASK)
+
#endif
diff --git a/include/asm-um/pgalloc.h b/include/asm-um/pgalloc.h
index 4620297e2cc7..4ffc0f9c5a3e 100644
--- a/include/asm-um/pgalloc.h
+++ b/include/asm-um/pgalloc.h
@@ -8,6 +8,7 @@
#define __UM_PGALLOC_H
#include "linux/mm.h"
+#include "asm/fixmap.h"
#define pmd_populate_kernel(mm, pmd, pte) \
set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte)))
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index 85b366b643a3..17fd515545da 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -62,12 +62,16 @@ extern unsigned long *empty_zero_page;
*/
extern unsigned long high_physmem;
-extern unsigned long end_vm;
#define VMALLOC_OFFSET (__va_space)
#define VMALLOC_START (((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END (end_vm)
+
+#if CONFIG_HIGHMEM
+# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
+#else
+# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
+#endif
#define _PAGE_PRESENT 0x001
#define _PAGE_NEWPAGE 0x002
@@ -333,6 +337,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
/* to find an entry in a page-table-directory. */
#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define __pgd_offset(address) pgd_index(address)
/* to find an entry in a page-table-directory */
#define pgd_offset(mm, address) \
@@ -341,6 +346,9 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+#define __pmd_offset(address) \
+ (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+
/* Find an entry in the second-level page table.. */
static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
{
diff --git a/include/asm-um/tlbflush.h b/include/asm-um/tlbflush.h
index fd55c6efb4d3..522aa30f7eaa 100644
--- a/include/asm-um/tlbflush.h
+++ b/include/asm-um/tlbflush.h
@@ -27,6 +27,7 @@ extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
extern void flush_tlb_kernel_vm(void);
extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void __flush_tlb_one(unsigned long addr);
static inline void flush_tlb_pgtables(struct mm_struct *mm,
unsigned long start, unsigned long end)