diff options
Diffstat (limited to 'arch/i386/mm/init.c')
-rw-r--r-- | arch/i386/mm/init.c | 180 |
1 files changed, 126 insertions, 54 deletions
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 296595644..cf258d6de 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -15,13 +15,17 @@ #include <linux/ptrace.h> #include <linux/mman.h> #include <linux/mm.h> +#include <linux/swap.h> +#include <linux/smp.h> +#ifdef CONFIG_BLK_DEV_INITRD +#include <linux/blk.h> +#endif #include <asm/system.h> -#include <asm/segment.h> +#include <asm/uaccess.h> #include <asm/pgtable.h> +#include <asm/dma.h> -extern void scsi_mem_init(unsigned long); -extern void sound_mem_init(void); extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); @@ -29,7 +33,7 @@ extern void show_net_buffers(void); * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode + * for a process dying in kernel mode, possibly leaving an inode * unused etc.. * * BAD_PAGETABLE is the accompanying page-table: it is initialized @@ -70,15 +74,15 @@ void show_mem(void) printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - i = high_memory >> PAGE_SHIFT; + i = max_mapnr; while (i-- > 0) { total++; - if (mem_map[i] & MAP_PAGE_RESERVED) + if (PageReserved(mem_map+i)) reserved++; - else if (!mem_map[i]) + else if (!mem_map[i].count) free++; else - shared += mem_map[i]-1; + shared += mem_map[i].count-1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); @@ -111,34 +115,90 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) * and SMM (for laptops with [34]86/SL chips) may need it. It is read * and write protected to detect null pointer references in the * kernel. + * It may also hold the MP configuration table when we are booting SMP. */ #if 0 memset((void *) 0, 0, PAGE_SIZE); #endif +#ifdef __SMP__ + if (!smp_scan_config(0x0,0x400)) /* Scan the bottom 1K for a signature */ + { + /* + * FIXME: Linux assumes you have 640K of base ram.. this continues + * the error... + */ + if (!smp_scan_config(639*0x400,0x400)) /* Scan the top 1K of base RAM */ + smp_scan_config(0xF0000,0x10000); /* Scan the 64K of bios */ + } + /* + * If it is an SMP machine we should know now, unless the configuration + * is in an EISA/MCA bus machine with an extended bios data area. I don't + * have such a machine so someone else can fill in the check of the EBDA + * here. + */ +/* smp_alloc_memory(8192); */ +#endif +#ifdef TEST_VERIFY_AREA + wp_works_ok = 0; +#endif start_mem = PAGE_ALIGN(start_mem); - address = 0; + address = PAGE_OFFSET; pg_dir = swapper_pg_dir; + /* unmap the original low memory mappings */ + pgd_val(pg_dir[0]) = 0; while (address < end_mem) { + /* + * The following code enabled 4MB page tables for the + * Intel Pentium cpu, unfortunately the SMP kernel can't + * handle the 4MB page table optimizations yet + */ +#ifndef __SMP__ + /* + * This will create page tables that + * span up to the next 4MB virtual + * memory boundary, but that's ok, + * we won't use that memory anyway. + */ + if (x86_capability & 8) { +#ifdef GAS_KNOWS_CR4 + __asm__("movl %%cr4,%%eax\n\t" + "orl $16,%%eax\n\t" + "movl %%eax,%%cr4" + : : :"ax"); +#else + __asm__(".byte 0x0f,0x20,0xe0\n\t" + "orl $16,%%eax\n\t" + ".byte 0x0f,0x22,0xe0" + : : :"ax"); +#endif + wp_works_ok = 1; + pgd_val(pg_dir[768]) = _PAGE_TABLE + _PAGE_4M + __pa(address); + pg_dir++; + address += 4*1024*1024; + continue; + } +#endif /* map the memory at virtual addr 0xC0000000 */ + /* pg_table is physical at this point */ pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[768])); if (!pg_table) { - pg_table = (pte_t *) start_mem; + pg_table = (pte_t *) __pa(start_mem); start_mem += PAGE_SIZE; } - /* also map it temporarily at 0x0000000 for init */ - pgd_val(pg_dir[0]) = _PAGE_TABLE | (unsigned long) pg_table; pgd_val(pg_dir[768]) = _PAGE_TABLE | (unsigned long) pg_table; pg_dir++; + /* now change pg_table to kernel virtual addresses */ + pg_table = (pte_t *) __va(pg_table); for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) { - if (address < end_mem) - *pg_table = mk_pte(address, PAGE_SHARED); - else - pte_clear(pg_table); + pte_t pte = mk_pte(address, PAGE_KERNEL); + if (address >= end_mem) + pte_val(pte) = 0; + set_pte(pg_table, pte); address += PAGE_SIZE; } } - invalidate(); + local_flush_tlb(); return free_area_init(start_mem, end_mem); } @@ -149,16 +209,25 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) int reservedpages = 0; int datapages = 0; unsigned long tmp; - extern int etext; + extern int _etext; end_mem &= PAGE_MASK; - high_memory = end_mem; + high_memory = (void *) end_mem; + max_mapnr = MAP_NR(end_mem); /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); /* mark usable pages in the mem_map[] */ - start_low_mem = PAGE_ALIGN(start_low_mem); + start_low_mem = PAGE_ALIGN(start_low_mem)+PAGE_OFFSET; + +#ifdef __SMP__ + /* + * But first pinch a few for the stack/trampoline stuff + */ + start_low_mem += PAGE_SIZE; /* 32bit startup code */ + start_low_mem = smp_alloc_memory(start_low_mem); /* AP processor stacks */ +#endif start_mem = PAGE_ALIGN(start_mem); /* @@ -166,53 +235,56 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) * They seem to have done something stupid with the floppy * controller as well.. */ - while (start_low_mem < 0x9f000) { - mem_map[MAP_NR(start_low_mem)] = 0; + while (start_low_mem < 0x9f000+PAGE_OFFSET) { + clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags); start_low_mem += PAGE_SIZE; } - while (start_mem < high_memory) { - mem_map[MAP_NR(start_mem)] = 0; + while (start_mem < end_mem) { + clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); start_mem += PAGE_SIZE; } -#ifdef CONFIG_SCSI - scsi_mem_init(high_memory); -#endif -#ifdef CONFIG_SOUND - sound_mem_init(); -#endif - for (tmp = 0 ; tmp < high_memory ; tmp += PAGE_SIZE) { - if (mem_map[MAP_NR(tmp)]) { - if (tmp >= 0xA0000 && tmp < 0x100000) + 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); + if (PageReserved(mem_map+MAP_NR(tmp))) { + if (tmp >= 0xA0000+PAGE_OFFSET && tmp < 0x100000+PAGE_OFFSET) reservedpages++; - else if (tmp < (unsigned long) &etext) + else if (tmp < (unsigned long) &_etext) codepages++; else datapages++; continue; } - mem_map[MAP_NR(tmp)] = 1; - free_page(tmp); + mem_map[MAP_NR(tmp)].count = 1; +#ifdef CONFIG_BLK_DEV_INITRD + if (!initrd_start || (tmp < initrd_start || tmp >= + initrd_end)) +#endif + free_page(tmp); } - tmp = nr_free_pages << PAGE_SHIFT; printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n", - tmp >> 10, - high_memory >> 10, + (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)); /* test if the WP bit is honoured in supervisor mode */ - wp_works_ok = -1; - pg0[0] = pte_val(mk_pte(0, PAGE_READONLY)); - invalidate(); - __asm__ __volatile__("movb 0,%%al ; movb %%al,0": : :"ax", "memory"); - pg0[0] = 0; - invalidate(); - if (wp_works_ok < 0) - wp_works_ok = 0; -#ifdef CONFIG_TEST_VERIFY_AREA - wp_works_ok = 0; -#endif + if (wp_works_ok < 0) { + unsigned char tmp_reg; + pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY)); + local_flush_tlb(); + __asm__ __volatile__( + "movb %0,%1 ; movb %1,%0" + :"=m" (*(char *) __va(0)), + "=q" (tmp_reg) + :/* no inputs */ + :"memory"); + pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_KERNEL)); + local_flush_tlb(); + if (wp_works_ok < 0) + wp_works_ok = 0; + } return; } @@ -220,18 +292,18 @@ void si_meminfo(struct sysinfo *val) { int i; - i = high_memory >> PAGE_SHIFT; + i = max_mapnr; val->totalram = 0; val->sharedram = 0; val->freeram = nr_free_pages << PAGE_SHIFT; val->bufferram = buffermem; while (i-- > 0) { - if (mem_map[i] & MAP_PAGE_RESERVED) + if (PageReserved(mem_map+i)) continue; val->totalram++; - if (!mem_map[i]) + if (!mem_map[i].count) continue; - val->sharedram += mem_map[i]-1; + val->sharedram += mem_map[i].count-1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; |