summaryrefslogtreecommitdiffstats
path: root/arch/i386/mm/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/mm/init.c')
-rw-r--r--arch/i386/mm/init.c180
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;