diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /arch/i386/mm | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'arch/i386/mm')
-rw-r--r-- | arch/i386/mm/Makefile | 4 | ||||
-rw-r--r-- | arch/i386/mm/bigmem.c | 33 | ||||
-rw-r--r-- | arch/i386/mm/fault.c | 22 | ||||
-rw-r--r-- | arch/i386/mm/init.c | 157 |
4 files changed, 140 insertions, 76 deletions
diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile index cee7d4e6d..d60bc1969 100644 --- a/arch/i386/mm/Makefile +++ b/arch/i386/mm/Makefile @@ -10,4 +10,8 @@ O_TARGET := mm.o O_OBJS := init.o fault.o ioremap.o extable.o +ifeq ($(CONFIG_BIGMEM),y) +O_OBJS += bigmem.o +endif + include $(TOPDIR)/Rules.make diff --git a/arch/i386/mm/bigmem.c b/arch/i386/mm/bigmem.c new file mode 100644 index 000000000..8da077927 --- /dev/null +++ b/arch/i386/mm/bigmem.c @@ -0,0 +1,33 @@ +/* + * BIGMEM IA32 code and variables. + * + * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de + * Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de + */ + +#include <linux/mm.h> +#include <linux/bigmem.h> + +unsigned long bigmem_start, bigmem_end; + +/* NOTE: fixmap_init alloc all the fixmap pagetables contigous on the + physical space so we can cache the place of the first one and move + around without checking the pgd every time. */ +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; + if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) + pgprot_val(kmap_prot) |= _PAGE_GLOBAL; +} diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index c3e423b21..1f7879005 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -109,7 +109,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) * If we're in an interrupt or have no user * context, we must not take the fault.. */ - if (in_interrupt() || mm == &init_mm) + if (in_interrupt() || !mm) goto no_context; down(&mm->mmap_sem); @@ -177,7 +177,7 @@ good_area: if (regs->eflags & VM_MASK) { unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT; if (bit < 32) - tsk->tss.screen_bitmap |= 1 << bit; + tsk->thread.screen_bitmap |= 1 << bit; } up(&mm->mmap_sem); return; @@ -191,9 +191,9 @@ bad_area: /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { - tsk->tss.cr2 = address; - tsk->tss.error_code = error_code; - tsk->tss.trap_no = 14; + tsk->thread.cr2 = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; force_sig(SIGSEGV, tsk); return; } @@ -243,9 +243,9 @@ no_context: else printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at virtual address %08lx\n",address); - __asm__("movl %%cr3,%0" : "=r" (page)); - printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n", - tsk->tss.cr3, page); + printk(" printing eip:\n"); + printk("%08lx\n", regs->eip); + asm("movl %%cr3,%0":"=r" (page)); page = ((unsigned long *) __va(page))[address >> 22]; printk(KERN_ALERT "*pde = %08lx\n", page); if (page & 1) { @@ -275,9 +275,9 @@ do_sigbus: * Send a sigbus, regardless of whether we were in kernel * or user mode. */ - tsk->tss.cr2 = address; - tsk->tss.error_code = error_code; - tsk->tss.trap_no = 14; + tsk->thread.cr2 = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; force_sig(SIGBUS, tsk); /* Kernel mode? Handle exceptions or die */ diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 703b8ca87..05684997f 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -2,6 +2,8 @@ * linux/arch/i386/mm/init.c * * Copyright (C) 1995 Linus Torvalds + * + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 */ #include <linux/config.h> @@ -20,6 +22,7 @@ #ifdef CONFIG_BLK_DEV_INITRD #include <linux/blk.h> #endif +#include <linux/bigmem.h> #include <asm/processor.h> #include <asm/system.h> @@ -27,6 +30,10 @@ #include <asm/pgtable.h> #include <asm/dma.h> #include <asm/fixmap.h> +#include <asm/e820.h> + +static unsigned long totalram = 0; +static unsigned long totalbig = 0; extern void show_net_buffers(void); extern unsigned long init_smp_mappings(unsigned long); @@ -148,6 +155,7 @@ void show_mem(void) { int i,free = 0,total = 0,reserved = 0; int shared = 0, cached = 0; + int bigmem = 0; printk("Mem-info:\n"); show_free_areas(); @@ -155,6 +163,8 @@ void show_mem(void) i = max_mapnr; while (i-- > 0) { total++; + if (PageBIGMEM(mem_map+i)) + bigmem++; if (PageReserved(mem_map+i)) reserved++; else if (PageSwapCache(mem_map+i)) @@ -165,6 +175,7 @@ void show_mem(void) shared += page_count(mem_map+i) - 1; } printk("%d pages of RAM\n",total); + printk("%d pages of BIGMEM\n",bigmem); printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); @@ -181,34 +192,6 @@ extern unsigned long free_area_init(unsigned long, unsigned long); extern char _text, _etext, _edata, __bss_start, _end; extern char __init_begin, __init_end; -#define X86_CR4_VME 0x0001 /* enable vm86 extensions */ -#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */ -#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */ -#define X86_CR4_DE 0x0008 /* enable debugging extensions */ -#define X86_CR4_PSE 0x0010 /* enable page size extensions */ -#define X86_CR4_PAE 0x0020 /* enable physical address extensions */ -#define X86_CR4_MCE 0x0040 /* Machine check enable */ -#define X86_CR4_PGE 0x0080 /* enable global pages */ -#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */ - -/* - * Save the cr4 feature set we're using (ie - * Pentium 4MB enable and PPro Global page - * enable), so that any CPU's that boot up - * after us can get the correct flags. - */ -unsigned long mmu_cr4_features __initdata = 0; - -static inline void set_in_cr4(unsigned long mask) -{ - mmu_cr4_features |= mask; - __asm__("movl %%cr4,%%eax\n\t" - "orl %0,%%eax\n\t" - "movl %%eax,%%cr4\n" - : : "irg" (mask) - :"ax"); -} - /* * allocate page table(s) for compile-time fixed mappings */ @@ -264,7 +247,7 @@ void set_fixmap (enum fixed_addresses idx, unsigned long phys) * This routines also unmaps the page at virtual kernel address 0, so * that we can trap those pesky NULL-reference errors in the kernel. */ -__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) { pgd_t * pg_dir; pte_t * pg_table; @@ -341,7 +324,12 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_ #endif local_flush_tlb(); +#ifndef CONFIG_BIGMEM return free_area_init(start_mem, end_mem); +#else + kmap_init(); /* run after fixmap_init */ + return free_area_init(start_mem, bigmem_end + PAGE_OFFSET); +#endif } /* @@ -350,7 +338,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_ * before and after the test are here to work-around some nasty CPU bugs. */ -__initfunc(void test_wp_bit(void)) +void __init test_wp_bit(void) { unsigned char tmp_reg; unsigned long old = pg0[0]; @@ -358,7 +346,6 @@ __initfunc(void test_wp_bit(void)) printk("Checking if this processor honours the WP bit even in supervisor mode... "); pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY)); local_flush_tlb(); - current->mm->mmap->vm_start += PAGE_SIZE; __asm__ __volatile__( "jmp 1f; 1:\n" "movb %0,%1\n" @@ -370,7 +357,6 @@ __initfunc(void test_wp_bit(void)) :"memory"); pg0[0] = old; local_flush_tlb(); - current->mm->mmap->vm_start -= PAGE_SIZE; if (boot_cpu_data.wp_works_ok < 0) { boot_cpu_data.wp_works_ok = 0; printk("No.\n"); @@ -381,7 +367,7 @@ __initfunc(void test_wp_bit(void)) printk(".\n"); } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { unsigned long start_low_mem = PAGE_SIZE; int codepages = 0; @@ -389,11 +375,21 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) int datapages = 0; int initpages = 0; unsigned long tmp; - unsigned long endbase; + int i, avail; end_mem &= PAGE_MASK; +#ifdef CONFIG_BIGMEM + bigmem_start = PAGE_ALIGN(bigmem_start); + bigmem_end &= PAGE_MASK; +#endif high_memory = (void *) end_mem; +#ifndef CONFIG_BIGMEM max_mapnr = num_physpages = MAP_NR(end_mem); +#else + max_mapnr = num_physpages = PHYSMAP_NR(bigmem_end); + /* cache the bigmem_mapnr */ + bigmem_mapnr = PHYSMAP_NR(bigmem_start); +#endif /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); @@ -413,22 +409,50 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) #endif start_mem = PAGE_ALIGN(start_mem); - /* - * IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 0x9F000. - * They seem to have done something stupid with the floppy - * controller as well.. - * The amount of available base memory is in WORD 40:13. + /* walk the whitelist, unreserving good memory */ - endbase = PAGE_OFFSET + ((*(unsigned short *)__va(0x413) * 1024) & PAGE_MASK); - while (start_low_mem < endbase) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags); - start_low_mem += PAGE_SIZE; - } + for (avail = i = 0; i < e820.nr_map; i++) { + unsigned long addr, end, size; - while (start_mem < end_mem) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); - start_mem += PAGE_SIZE; + if (e820.map[i].type != E820_RAM) /* not usable memory */ + continue; + addr = e820.map[i].addr; + size = e820.map[i].size; + + /* Silently ignore memory regions starting above 4gb */ + if (addr != e820.map[i].addr) + continue; + + printk("memory region: %luk @ %08lx\n", size >> 10, addr ); + + /* Make sure we don't get fractional pages */ + end = PAGE_OFFSET + ((addr + size) & PAGE_MASK); + addr= PAGE_OFFSET + PAGE_ALIGN(addr); + + for ( ; addr < end; addr += PAGE_SIZE) { + + /* this little bit of grossness is for dealing + * with memory borrowing for system bookkeeping + * (smp stacks, zero page, kernel code, etc) + * without having to go back and edit the e820 + * map to compensate. + * + * if we're in low memory (<1024k), we need to + * avoid the smp stack and zero page. + * if we're in high memory, we need to avoid + * the kernel code. + * in any case, we don't want to hack mem_map + * entries above end_mem. + */ + if ( (addr < start_low_mem) + || (addr >= (HIGH_MEMORY + PAGE_OFFSET)&& addr <= start_mem) + || (addr > end_mem) ) + continue; + + clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags); + } } + for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) { if (tmp >= MAX_DMA_ADDRESS) clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); @@ -449,22 +473,35 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) continue; } set_page_count(mem_map+MAP_NR(tmp), 1); + totalram += PAGE_SIZE; #ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || (tmp < initrd_start || tmp >= - initrd_end)) + if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end)) #endif free_page(tmp); } - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", +#ifdef CONFIG_BIGMEM + for (tmp = bigmem_start; tmp < bigmem_end; tmp += PAGE_SIZE) { + clear_bit(PG_reserved, &mem_map[PHYSMAP_NR(tmp)].flags); + set_bit(PG_BIGMEM, &mem_map[PHYSMAP_NR(tmp)].flags); + atomic_set(&mem_map[PHYSMAP_NR(tmp)].count, 1); + free_page(tmp + PAGE_OFFSET); + totalbig += PAGE_SIZE; + } + totalram += totalbig; +#endif + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %dk bigmem)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), - initpages << (PAGE_SHIFT-10)); + initpages << (PAGE_SHIFT-10), + (int) (totalbig >> 10) + ); if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); + } void free_initmem(void) @@ -476,28 +513,18 @@ void free_initmem(void) mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); set_page_count(mem_map+MAP_NR(addr), 1); free_page(addr); + totalram += PAGE_SIZE; } printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } void si_meminfo(struct sysinfo *val) { - int i; - - i = max_mapnr; - val->totalram = 0; + val->totalram = totalram; val->sharedram = 0; val->freeram = nr_free_pages << PAGE_SHIFT; val->bufferram = atomic_read(&buffermem); - while (i-- > 0) { - if (PageReserved(mem_map+i)) - continue; - val->totalram++; - if (!page_count(mem_map+i)) - continue; - val->sharedram += page_count(mem_map+i) - 1; - } - val->totalram <<= PAGE_SHIFT; - val->sharedram <<= PAGE_SHIFT; + val->totalbig = totalbig; + val->freebig = nr_free_bigpages << PAGE_SHIFT; return; } |