URL
https://opencores.org/ocsvn/or1k_old/or1k_old/trunk
Subversion Repositories or1k_old
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k_old/trunk/rc203soc/sw/uClinux/arch/i386/mm
- from Rev 1765 to Rev 1782
- ↔ Reverse comparison
Rev 1765 → Rev 1782
/init.c
0,0 → 1,324
/* |
* linux/arch/i386/mm/init.c |
* |
* Copyright (C) 1995 Linus Torvalds |
*/ |
|
#include <linux/config.h> |
#include <linux/signal.h> |
#include <linux/sched.h> |
#include <linux/head.h> |
#include <linux/kernel.h> |
#include <linux/errno.h> |
#include <linux/string.h> |
#include <linux/types.h> |
#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/pgtable.h> |
#include <asm/dma.h> |
|
#if 0 |
/* |
* The SMP kernel can't handle the 4MB page table optimizations yet |
*/ |
#ifdef __SMP__ |
#undef USE_PENTIUM_MM |
#endif |
#endif |
|
const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; |
|
extern void die_if_kernel(char *,struct pt_regs *,long); |
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 |
* unused etc.. |
* |
* BAD_PAGETABLE is the accompanying page-table: it is initialized |
* to point to BAD_PAGE entries. |
* |
* ZERO_PAGE is a special page that is used for zero-initialized |
* data and COW. |
*/ |
pte_t * __bad_pagetable(void) |
{ |
extern char empty_bad_page_table[PAGE_SIZE]; |
|
__asm__ __volatile__("cld ; rep ; stosl": |
:"a" (pte_val(BAD_PAGE)), |
"D" ((long) empty_bad_page_table), |
"c" (PAGE_SIZE/4) |
:"di","cx"); |
return (pte_t *) empty_bad_page_table; |
} |
|
pte_t __bad_page(void) |
{ |
extern char empty_bad_page[PAGE_SIZE]; |
|
__asm__ __volatile__("cld ; rep ; stosl": |
:"a" (0), |
"D" ((long) empty_bad_page), |
"c" (PAGE_SIZE/4) |
:"di","cx"); |
return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED)); |
} |
|
void show_mem(void) |
{ |
int i,free = 0,total = 0,reserved = 0; |
int shared = 0; |
|
printk("Mem-info:\n"); |
show_free_areas(); |
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); |
i = high_memory >> PAGE_SHIFT; |
while (i-- > 0) { |
total++; |
if (PageReserved(mem_map+i)) |
reserved++; |
else if (!mem_map[i].count) |
free++; |
else |
shared += mem_map[i].count-1; |
} |
printk("%d pages of RAM\n",total); |
printk("%d free pages\n",free); |
printk("%d reserved pages\n",reserved); |
printk("%d pages shared\n",shared); |
show_buffers(); |
#ifdef CONFIG_NET |
show_net_buffers(); |
#endif |
} |
|
extern unsigned long free_area_init(unsigned long, unsigned long); |
|
/* |
* paging_init() sets up the page tables - note that the first 4MB are |
* already mapped by head.S. |
* |
* This routines also unmaps the page at virtual kernel address 0, so |
* that we can trap those pesky NULL-reference errors in the kernel. |
*/ |
unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) |
{ |
pgd_t * pg_dir; |
pte_t * pg_table; |
unsigned long tmp; |
unsigned long address; |
|
/* |
* Physical page 0 is special; it's not touched by Linux since BIOS |
* 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 */ |
{ |
if(!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. |
* |
* there is a real-mode segmented pointer pointing to the |
* 4K EBDA area at 0x40E, calculate and scan it here: |
*/ |
address = *(unsigned short *)phys_to_virt(0x40E); |
address<<=4; |
smp_scan_config(address, 0x1000); |
} |
} |
} |
/* |
* 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; |
pg_dir = swapper_pg_dir; |
while (address < end_mem) { |
#ifdef USE_PENTIUM_MM |
/* |
* 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[0]) = _PAGE_TABLE | _PAGE_4M | address; |
pgd_val(pg_dir[USER_PGD_PTRS]) = _PAGE_TABLE | _PAGE_4M | address; |
pg_dir++; |
address += 4*1024*1024; |
continue; |
} |
#endif |
/* map the memory at virtual addr PAGE_OFFSET */ |
pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[USER_PGD_PTRS])); |
if (!pg_table) { |
pg_table = (pte_t *) 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[USER_PGD_PTRS]) = _PAGE_TABLE | (unsigned long) pg_table; |
pg_dir++; |
for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) { |
if (address < end_mem) |
set_pte(pg_table, mk_pte(address, PAGE_SHARED)); |
else |
pte_clear(pg_table); |
address += PAGE_SIZE; |
} |
} |
local_flush_tlb(); |
return free_area_init(start_mem, end_mem); |
} |
|
void mem_init(unsigned long start_mem, unsigned long end_mem) |
{ |
unsigned long start_low_mem = PAGE_SIZE; |
int codepages = 0; |
int reservedpages = 0; |
int datapages = 0; |
unsigned long tmp; |
extern int _etext; |
|
end_mem &= PAGE_MASK; |
high_memory = 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); |
|
#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); |
|
/* |
* IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 0x9F000. |
* They seem to have done something stupid with the floppy |
* controller as well.. |
*/ |
while (start_low_mem < 0x9f000) { |
clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags); |
start_low_mem += PAGE_SIZE; |
} |
|
while (start_mem < high_memory) { |
clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); |
start_mem += PAGE_SIZE; |
} |
for (tmp = 0 ; tmp < high_memory ; 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 && tmp < 0x100000) |
reservedpages++; |
else if (tmp < (unsigned long) &_etext) |
codepages++; |
else |
datapages++; |
continue; |
} |
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, |
codepages << (PAGE_SHIFT-10), |
reservedpages << (PAGE_SHIFT-10), |
datapages << (PAGE_SHIFT-10)); |
/* test if the WP bit is honoured in supervisor mode */ |
if (wp_works_ok < 0) { |
pg0[0] = pte_val(mk_pte(0, PAGE_READONLY)); |
local_flush_tlb(); |
__asm__ __volatile__("movb 0,%%al ; movb %%al,0": : :"ax", "memory"); |
pg0[0] = 0; |
local_flush_tlb(); |
if (wp_works_ok < 0) |
wp_works_ok = 0; |
} |
return; |
} |
|
void si_meminfo(struct sysinfo *val) |
{ |
int i; |
|
i = high_memory >> PAGE_SHIFT; |
val->totalram = 0; |
val->sharedram = 0; |
val->freeram = nr_free_pages << PAGE_SHIFT; |
val->bufferram = buffermem; |
while (i-- > 0) { |
if (PageReserved(mem_map+i)) |
continue; |
val->totalram++; |
if (!mem_map[i].count) |
continue; |
val->sharedram += mem_map[i].count-1; |
} |
val->totalram <<= PAGE_SHIFT; |
val->sharedram <<= PAGE_SHIFT; |
return; |
} |
/fault.c
0,0 → 1,175
/* |
* linux/arch/i386/mm/fault.c |
* |
* Copyright (C) 1995 Linus Torvalds |
*/ |
|
#include <linux/signal.h> |
#include <linux/sched.h> |
#include <linux/head.h> |
#include <linux/kernel.h> |
#include <linux/errno.h> |
#include <linux/string.h> |
#include <linux/types.h> |
#include <linux/ptrace.h> |
#include <linux/mman.h> |
#include <linux/mm.h> |
|
#include <asm/system.h> |
#include <asm/segment.h> |
#include <asm/pgtable.h> |
|
extern void die_if_kernel(const char *,struct pt_regs *,long); |
|
asmlinkage void do_invalid_op (struct pt_regs *, unsigned long); |
|
extern int pentium_f00f_bug; |
|
/* |
* This routine handles page faults. It determines the address, |
* and the problem, and then passes it off to one of the appropriate |
* routines. |
* |
* error_code: |
* bit 0 == 0 means no page found, 1 means protection fault |
* bit 1 == 0 means read, 1 means write |
* bit 2 == 0 means kernel, 1 means user-mode |
*/ |
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) |
{ |
void (*handler)(struct task_struct *, |
struct vm_area_struct *, |
unsigned long, |
int); |
struct task_struct *tsk = current; |
struct mm_struct *mm = tsk->mm; |
struct vm_area_struct * vma; |
unsigned long address; |
unsigned long page; |
int write; |
|
/* get the address */ |
__asm__("movl %%cr2,%0":"=r" (address)); |
down(&mm->mmap_sem); |
vma = find_vma(mm, address); |
if (!vma) |
goto bad_area; |
if (vma->vm_start <= address) |
goto good_area; |
if (!(vma->vm_flags & VM_GROWSDOWN)) |
goto bad_area; |
if (error_code & 4) { |
/* |
* accessing the stack below %esp is always a bug. |
* The "+ 32" is there due to some instructions (like |
* pusha) doing pre-decrement on the stack and that |
* doesn't show up until later.. |
*/ |
if (address + 32 < regs->esp) |
goto bad_area; |
} |
if (expand_stack(vma, address)) |
goto bad_area; |
/* |
* Ok, we have a good vm_area for this memory access, so |
* we can handle it.. |
*/ |
good_area: |
write = 0; |
handler = do_no_page; |
switch (error_code & 3) { |
default: /* 3: write, present */ |
handler = do_wp_page; |
#ifdef TEST_VERIFY_AREA |
if (regs->cs == KERNEL_CS) |
printk("WP fault at %08lx\n", regs->eip); |
#endif |
/* fall through */ |
case 2: /* write, not present */ |
if (!(vma->vm_flags & VM_WRITE)) |
goto bad_area; |
write++; |
break; |
case 1: /* read, present */ |
goto bad_area; |
case 0: /* read, not present */ |
if (!(vma->vm_flags & (VM_READ | VM_EXEC))) |
goto bad_area; |
} |
handler(tsk, vma, address, write); |
up(&mm->mmap_sem); |
/* |
* Did it hit the DOS screen memory VA from vm86 mode? |
*/ |
if (regs->eflags & VM_MASK) { |
unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT; |
if (bit < 32) |
tsk->tss.screen_bitmap |= 1 << bit; |
} |
return; |
|
/* |
* Something tried to access memory that isn't in our memory map.. |
* Fix it, but check if it's kernel or user first.. |
*/ |
bad_area: |
up(&mm->mmap_sem); |
if (error_code & 4) { |
tsk->tss.cr2 = address; |
tsk->tss.error_code = error_code; |
tsk->tss.trap_no = 14; |
force_sig(SIGSEGV, tsk); |
return; |
} |
|
/* |
* Pentium F0 0F C7 C8 bug workaround: |
*/ |
if ( pentium_f00f_bug ) { |
unsigned long nr; |
extern struct { |
unsigned short limit; |
unsigned long addr __attribute__((packed)); |
} idt_descriptor; |
|
nr = (address - idt_descriptor.addr) >> 3; |
|
if (nr == 6) { |
do_invalid_op(regs, 0); |
return; |
} |
} |
|
|
/* |
* Oops. The kernel tried to access some bad page. We'll have to |
* terminate things with extreme prejudice. |
* |
* First we check if it was the bootup rw-test, though.. |
*/ |
if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) { |
wp_works_ok = 1; |
pg0[0] = pte_val(mk_pte(0, PAGE_SHARED)); |
flush_tlb(); |
printk("This processor honours the WP bit even when in supervisor mode. Good.\n"); |
return; |
} |
if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) |
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); |
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); |
page = ((unsigned long *) page)[address >> 22]; |
printk(KERN_ALERT "*pde = %08lx\n", page); |
if (page & 1) { |
page &= PAGE_MASK; |
address &= 0x003ff000; |
page = ((unsigned long *) page)[address >> PAGE_SHIFT]; |
printk(KERN_ALERT "*pte = %08lx\n", page); |
} |
die_if_kernel("Oops", regs, error_code); |
do_exit(SIGKILL); |
} |
/Makefile
0,0 → 1,13
# |
# Makefile for the linux i386-specific parts of the memory manager. |
# |
# Note! Dependencies are done automagically by 'make dep', which also |
# removes any old dependencies. DON'T put your own dependencies here |
# unless it's something special (ie not a .c file). |
# |
# Note 2! The CFLAGS definition is now in the main makefile... |
|
O_TARGET := mm.o |
O_OBJS := init.o fault.o |
|
include $(TOPDIR)/Rules.make |