summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdike <jdike>2003-12-16 16:21:54 +0000
committerjdike <jdike>2003-12-16 16:21:54 +0000
commit7d462f7850e534d789a6b4d1c1f58d99a95d64a7 (patch)
tree40771a1f8aafdf3cca95b8b8d14ba99077af8db8
parent3c0c3e7adf61899a435bb58bb332875cda5c2750 (diff)
downloaduml-history-7d462f7850e534d789a6b4d1c1f58d99a95d64a7.tar.gz
Fixed highmem support.
-rw-r--r--arch/um/include/mem_user.h10
-rw-r--r--arch/um/kernel/mem.c74
-rw-r--r--arch/um/kernel/physmem.c67
-rw-r--r--arch/um/kernel/um_arch.c24
-rw-r--r--include/asm-um/pgtable.h1
5 files changed, 134 insertions, 42 deletions
diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h
index b0e01a9..fe0c298 100644
--- a/arch/um/include/mem_user.h
+++ b/arch/um/include/mem_user.h
@@ -49,19 +49,21 @@ extern int iomem_size;
extern unsigned long host_task_size;
extern unsigned long task_size;
+extern void check_devanon(void);
extern int init_mem_user(void);
extern int create_mem_file(unsigned long len);
extern void setup_memory(void *entry);
extern unsigned long find_iomem(char *driver, unsigned long *len_out);
-extern int init_maps(unsigned long len);
+extern int init_maps(unsigned long physmem, unsigned long iomem,
+ unsigned long highmem);
extern unsigned long get_vm(unsigned long len);
extern void setup_physmem(unsigned long start, unsigned long usable,
- unsigned long len);
+ unsigned long len, unsigned long highmem);
extern void add_iomem(char *name, int fd, unsigned long size);
extern unsigned long phys_offset(unsigned long phys);
extern void unmap_physmem(void);
-extern int map_memory(unsigned long virt, unsigned long phys,
- unsigned long len, int r, int w, int x);
+extern void map_memory(unsigned long virt, unsigned long phys,
+ unsigned long len, int r, int w, int x);
extern int protect_memory(unsigned long addr, unsigned long len,
int r, int w, int x, int must_succeed);
extern unsigned long get_kmem_end(void);
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index aba6258..8dd6327 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -40,14 +40,31 @@ static void map_cb(void *unused)
map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
}
-void mem_init(void)
+#ifdef CONFIG_HIGHMEM
+static void setup_highmem(unsigned long highmem_start,
+ unsigned long highmem_len)
{
- unsigned long start;
+ struct page *page;
+ unsigned long highmem_pfn;
+ int i;
-#ifdef CONFIG_HIGHMEM
- highmem_start_page = phys_page(__pa(high_physmem));
+ highmem_start_page = virt_to_page(highmem_start);
+
+ highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
+ for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
+ page = &mem_map[highmem_pfn + i];
+ ClearPageReserved(page);
+ set_bit(PG_highmem, &page->flags);
+ atomic_set(&page->count, 1);
+ __free_page(page);
+ }
+}
#endif
+void mem_init(void)
+{
+ unsigned long start;
+
/* clear the zero-page */
memset((void *) empty_zero_page, 0, PAGE_SIZE);
@@ -74,6 +91,10 @@ void mem_init(void)
printk(KERN_INFO "Memory: %luk available\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
kmalloc_ok = 1;
+
+#ifdef CONFIG_HIGHMEM
+ setup_highmem(end_iomem, highmem);
+#endif
}
static void __init fixrange_init(unsigned long start, unsigned long end,
@@ -106,6 +127,47 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
}
}
+#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;
+}
+
+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();
+}
+
+#endif /* CONFIG_HIGHMEM */
+
void paging_init(void)
{
unsigned long zones_size[MAX_NR_ZONES], vaddr;
@@ -115,8 +177,7 @@ void paging_init(void)
empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++)
zones_size[i] = 0;
- zones_size[0] = (high_physmem >> PAGE_SHIFT) -
- (uml_physmem >> PAGE_SHIFT);
+ zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
zones_size[2] = highmem >> PAGE_SHIFT;
free_area_init(zones_size);
@@ -129,7 +190,6 @@ void paging_init(void)
#if CONFIG_HIGHMEM
init_highmem();
- setup_highmem(highmem);
#endif
}
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 0ccab50..787c59c 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -133,24 +133,36 @@ unsigned long to_phys(void *virt)
return(((unsigned long) virt) - uml_physmem);
}
-int init_maps(unsigned long len)
+int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
{
struct page *p, *map;
- int i, n;
+ unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
+ unsigned long iomem_len, iomem_pages, total_len, total_pages;
+ int i;
+
+ phys_pages = physmem >> PAGE_SHIFT;
+ phys_len = phys_pages * sizeof(struct page);
+
+ iomem_pages = iomem >> PAGE_SHIFT;
+ iomem_len = iomem_pages * sizeof(struct page);
+
+ highmem_pages = highmem >> PAGE_SHIFT;
+ highmem_len = highmem_pages * sizeof(struct page);
- n = len >> PAGE_SHIFT;
- len = n * sizeof(struct page);
+ total_pages = phys_pages + iomem_pages + highmem_pages;
+ total_len = phys_len + iomem_pages + highmem_len;
if(kmalloc_ok){
- map = kmalloc(len, GFP_KERNEL);
- if(map == NULL) map = vmalloc(len);
+ map = kmalloc(total_len, GFP_KERNEL);
+ if(map == NULL)
+ map = vmalloc(total_len);
}
- else map = alloc_bootmem_low_pages(len);
+ else map = alloc_bootmem_low_pages(total_len);
if(map == NULL)
return(-ENOMEM);
- for(i = 0; i < n; i++){
+ for(i = 0; i < total_pages; i++){
p = &map[i];
set_page_count(p, 0);
SetPageReserved(p);
@@ -158,22 +170,23 @@ int init_maps(unsigned long len)
}
mem_map = map;
- max_mapnr = n;
+ max_mapnr = total_pages;
return(0);
}
-struct page *__virt_to_page(const unsigned long virt)
+struct page *phys_to_page(const unsigned long phys)
{
- int index = (virt - uml_physmem) >> PAGE_SHIFT;
+ return(&mem_map[phys >> PAGE_SHIFT]);
+}
- return(&mem_map[index]);
+struct page *__virt_to_page(const unsigned long virt)
+{
+ return(&mem_map[__pa(virt) >> PAGE_SHIFT]);
}
unsigned long page_to_phys(struct page *page)
{
- int index = page - mem_map;
-
- return(virt_to_phys((void *) (uml_physmem + (index << PAGE_SHIFT))));
+ return((page - mem_map) << PAGE_SHIFT);
}
pte_t mk_pte(struct page *page, pgprot_t pgprot)
@@ -195,27 +208,30 @@ unsigned long get_kmem_end(void)
return(kmem_top);
}
-int map_memory(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x)
+void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
+ int r, int w, int x)
{
__u64 offset;
- int fd;
+ int fd, err;
fd = phys_mapping(phys, &offset);
- return(os_map_memory((void *) virt, fd, offset, len, r, w, x));
+ err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
+ if(err)
+ panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
+ "err = %d\n", virt, fd, offset, len, r, w, x, err);
}
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
void setup_physmem(unsigned long start, unsigned long reserve_end,
- unsigned long len)
+ unsigned long len, unsigned long highmem)
{
unsigned long reserve = reserve_end - start;
int pfn = PFN_UP(__pa(reserve_end));
int delta = (len - reserve) >> PAGE_SHIFT;
int err, offset, bootmap_size;
- physmem_fd = create_mem_file(len);
+ physmem_fd = create_mem_file(len + highmem);
offset = uml_reserved - uml_physmem;
err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
@@ -240,11 +256,11 @@ int phys_mapping(unsigned long phys, __u64 *offset_out)
fd = desc->fd;
*offset_out = desc->offset;
}
- else if((phys >= 0) && (phys < physmem_size)){
+ else if(phys < physmem_size){
fd = physmem_fd;
*offset_out = phys;
}
- else {
+ else if(phys < __pa(end_iomem)){
struct iomem_region *region = iomem_regions;
while(region != NULL){
@@ -257,6 +273,11 @@ int phys_mapping(unsigned long phys, __u64 *offset_out)
region = region->next;
}
}
+ else if(phys < __pa(end_iomem) + highmem){
+ fd = physmem_fd;
+ *offset_out = phys - iomem_size;
+ }
+
return(fd);
}
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 57b42ba..e8aeb22 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -336,9 +336,15 @@ int linux_main(int argc, char **argv)
#endif
highmem = 0;
- max_physmem = get_kmem_end() - uml_physmem - MIN_VMALLOC;
- if(physmem_size > max_physmem){
- highmem = physmem_size - max_physmem;
+ iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
+ max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
+
+ /* Zones have to begin on a 1 << MAX_ORDER page boundary,
+ * so this makes sure that's true for highmem
+ */
+ max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
+ if(physmem_size + iomem_size > max_physmem){
+ highmem = physmem_size + iomem_size - max_physmem;
physmem_size -= highmem;
#ifndef CONFIG_HIGHMEM
highmem = 0;
@@ -348,15 +354,16 @@ int linux_main(int argc, char **argv)
}
high_physmem = uml_physmem + physmem_size;
- high_memory = (void *) high_physmem;
- end_iomem = high_physmem + PAGE_SIZE + iomem_size;
+ end_iomem = high_physmem + iomem_size;
+ high_memory = (void *) end_iomem;
start_vm = VMALLOC_START;
- setup_physmem(uml_physmem, uml_reserved, physmem_size);
- if(init_maps(physmem_size)){
+ setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
+ if(init_maps(physmem_size, iomem_size, highmem)){
printf("Failed to allocate mem_map for %ld bytes of physical "
- "memory\n", physmem_size);
+ "memory and %ld bytes of highmem\n", physmem_size,
+ highmem);
exit(1);
}
@@ -410,6 +417,7 @@ void __init check_bugs(void)
arch_check_bugs();
check_ptrace();
check_sigio();
+ check_devanon();
}
/*
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index a226925..798e47d 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -206,6 +206,7 @@ static inline void pgd_clear(pgd_t * pgdp) { }
#define pte_page(pte) virt_to_page(__va(pte_val(pte)))
#define pmd_page(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+extern struct page *phys_to_page(const unsigned long phys);
extern struct page *__virt_to_page(const unsigned long virt);
#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)