diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-01-27 23:45:22 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-01-27 23:45:22 +0000 |
commit | 5b35aa5cd29bb111d847b2a2ed18110acbfb1f44 (patch) | |
tree | c7bbaa1137528330d3c74d14056ef7016a52be72 /arch/sh | |
parent | 511bcd7c5924ce9e98ad1cb851988f7448dfef0f (diff) |
Merge with Linux 2.3.24.
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/kernel/entry.S | 11 | ||||
-rw-r--r-- | arch/sh/kernel/irq_onchip.c | 8 | ||||
-rw-r--r-- | arch/sh/kernel/setup.c | 157 | ||||
-rw-r--r-- | arch/sh/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/sh/lib/memchr.S | 26 | ||||
-rw-r--r-- | arch/sh/mm/init.c | 163 |
6 files changed, 237 insertions, 130 deletions
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S index bd9c7bb39..ac5a075c0 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/entry.S @@ -149,7 +149,7 @@ initial_page_write: /* Unwind the stack and jmp to the debug entry */ debug: add #4,r15 ! skip syscall number - ldc.l @r15+,ssr + mov.l @r15+,r11 ! SSR mov.l @r15+,r10 ! original stack mov.l @r15+,r0 mov.l @r15+,r1 @@ -164,6 +164,7 @@ debug: or r9,r14 ldc r14,sr ! here, change the register bank mov r10,k0 + mov r11,k1 mov.l @r15+,r8 mov.l @r15+,r9 mov.l @r15+,r10 @@ -180,7 +181,7 @@ debug: ! mov.l 9f,k0 jmp @k0 - nop + ldc k1,ssr .balign 4 8: .long 0x300000f0 9: .long 0xa0000100 @@ -371,7 +372,7 @@ ret_with_reschedule: ! restore_all: add #4,r15 ! skip syscall number - ldc.l @r15+,ssr + mov.l @r15+,r11 ! SSR mov.l @r15+,r10 ! original stack mov.l @r15+,r0 mov.l @r15+,r1 @@ -386,6 +387,7 @@ restore_all: or r9,r14 ldc r14,sr ! here, change the register bank mov r10,k0 + mov r11,k1 mov.l @r15+,r8 mov.l @r15+,r9 mov.l @r15+,r10 @@ -399,6 +401,7 @@ restore_all: lds.l @r15+,pr ldc.l @r15+,spc mov k0,r15 + ldc k1,ssr rte nop @@ -515,7 +518,7 @@ none: .data ENTRY(exception_handling_table) - .long none /* XXX: Avoid spurious interrupt */ + .long error .long error .long tlb_miss_load .long tlb_miss_store diff --git a/arch/sh/kernel/irq_onchip.c b/arch/sh/kernel/irq_onchip.c index b4ba54f31..0ed3400ef 100644 --- a/arch/sh/kernel/irq_onchip.c +++ b/arch/sh/kernel/irq_onchip.c @@ -89,29 +89,33 @@ static struct hw_interrupt_type onChip_irq_type = { void disable_onChip_irq(unsigned int irq) { + unsigned long val, flags; /* Set priority in IPR to 0 */ int offset = ipr_data[irq-TIMER_IRQ].offset; unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE); unsigned short mask = 0xffff ^ (0xf << (offset%16)); - unsigned long val; + save_and_cli(flags); val = ctrl_inw(intc_ipr_address); val &= mask; ctrl_outw(val, intc_ipr_address); + restore_flags(flags); } static void enable_onChip_irq(unsigned int irq) { + unsigned long val, flags; /* Set priority in IPR back to original value */ int offset = ipr_data[irq-TIMER_IRQ].offset; int priority = ipr_data[irq-TIMER_IRQ].priority; unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE); unsigned short value = (priority << (offset%16)); - unsigned long val; + save_and_cli(flags); val = ctrl_inw(intc_ipr_address); val |= value; ctrl_outw(val, intc_ipr_address); + restore_flags(flags); } void make_onChip_irq(unsigned int irq) diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 59c97a66b..deb532300 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -28,14 +28,17 @@ #ifdef CONFIG_BLK_DEV_RAM #include <linux/blk.h> #endif -#include <asm/processor.h> +#include <linux/bootmem.h> #include <linux/console.h> +#include <asm/processor.h> +#include <asm/page.h> #include <asm/pgtable.h> #include <asm/uaccess.h> #include <asm/system.h> #include <asm/io.h> #include <asm/smp.h> + /* * Machine setup.. */ @@ -62,7 +65,6 @@ extern int _text, _etext, _edata, _end; #define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c)) #define INITRD_START (*(unsigned long *) (PARAM+0x010)) #define INITRD_SIZE (*(unsigned long *) (PARAM+0x014)) -#define MEMORY_END (*(unsigned long *) (PARAM+0x018)) /* ... */ #define COMMAND_LINE ((char *) (PARAM+0x100)) #define COMMAND_LINE_SIZE 256 @@ -105,11 +107,67 @@ static struct resource rom_resources[MAXROMS] = { { "Video ROM", 0xc0000, 0xc7fff } }; -void __init setup_arch(char **cmdline_p, - unsigned long * memory_start_p, - unsigned long * memory_end_p) +static unsigned long memory_start, memory_end; + +unsigned long __init memparse(char *ptr, char **retptr) { - unsigned long memory_start, memory_end; + unsigned long ret; + + ret = simple_strtoul(ptr, retptr, 0); + + if (**retptr == 'K' || **retptr == 'k') { + ret <<= 10; + (*retptr)++; + } + else if (**retptr == 'M' || **retptr == 'm') { + ret <<= 20; + (*retptr)++; + } + return ret; +} /* memparse */ + +static inline void parse_mem_cmdline (char ** cmdline_p) +{ + char c = ' ', *to = command_line, *from = COMMAND_LINE; + int len = 0; + + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + + memory_start = (unsigned long)__va(0)+__MEMORY_START; + /* Default is 4Mbyte. */ + memory_end = (unsigned long)__va(0x00400000)+__MEMORY_START; + + for (;;) { + /* + * "mem=XXX[kKmM]" defines a size of memory. + */ + if (c == ' ' && !memcmp(from, "mem=", 4)) { + if (to != command_line) + to--; + { + unsigned long mem_size; + + mem_size = memparse(from+4, &from); + memory_end = memory_start + mem_size; + } + } + c = *(from++); + if (!c) + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *(to++) = c; + } + *to = '\0'; + *cmdline_p = command_line; +} + +void __init setup_arch(char **cmdline_p) +{ + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn, max_low_pfn; ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); @@ -118,12 +176,9 @@ void __init setup_arch(char **cmdline_p, rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif + if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; - - memory_start = (unsigned long) &_end; - memory_end = MEMORY_END; - init_mm.start_code = (unsigned long)&_text; init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; @@ -134,21 +189,73 @@ void __init setup_arch(char **cmdline_p, data_resource.start = virt_to_bus(&_etext); data_resource.end = virt_to_bus(&_edata)-1; - /* Save unparsed command line copy for /proc/cmdline */ - memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + parse_mem_cmdline(cmdline_p); - memcpy(command_line, COMMAND_LINE, COMMAND_LINE_SIZE); - command_line[COMMAND_LINE_SIZE-1] = '\0'; +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) - /* Not support "mem=XXX[kKmM]" command line option. */ - *cmdline_p = command_line; + /* + * partially used pages are not usable - thus + * we are rounding upwards: + */ + start_pfn = PFN_UP(__pa(&_end)-__MEMORY_START); - memory_end &= PAGE_MASK; - ram_resources[1].end = memory_end-1; + /* + * Find the highest page frame number we have available + */ + max_pfn = PFN_DOWN(__pa(memory_end)-__MEMORY_START); - *memory_start_p = memory_start; - *memory_end_p = memory_end; + /* + * Determine low and high memory ranges: + */ + max_low_pfn = max_pfn; + + /* + * Initialize the boot-time allocator (with low memory only): + */ + bootmap_size = init_bootmem(start_pfn, max_low_pfn); + + /* + * FIXME: what about high memory? + */ + ram_resources[1].end = PFN_PHYS(max_low_pfn) + __MEMORY_START; + + /* + * Register fully available low RAM pages with the bootmem allocator. + */ + { + unsigned long curr_pfn, last_pfn, size; + + /* + * We are rounding up the start address of usable memory: + */ + curr_pfn = PFN_UP(0); + /* + * ... and at the end of the usable range downwards: + */ + last_pfn = PFN_DOWN(memory_end-__MEMORY_START); + + if (last_pfn > max_low_pfn) + last_pfn = max_low_pfn; + + size = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); + } + /* + * Reserve the kernel text and + * Reserve the bootmem bitmap itself as well. We do this in two + * steps (first step was init_bootmem()) because this catches + * the (very unlikely) case of us accidentally initializing the + * bootmem allocator with an invalid RAM area. + */ + reserve_bootmem(PAGE_SIZE, PFN_PHYS(start_pfn) + bootmap_size); + + /* + * reserve physical page 0 - it's a special BIOS page on many boxes, + * enabling clean reboots, SMP operation, laptop functions. + */ + reserve_bootmem(0, PAGE_SIZE); #ifdef CONFIG_BLK_DEV_INITRD if (LOADER_TYPE) { @@ -156,10 +263,12 @@ void __init setup_arch(char **cmdline_p, initrd_end = initrd_start+INITRD_SIZE; if (initrd_end > memory_end) { printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,memory_end); + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_end,memory_end); initrd_start = 0; - } + } else + reserve_bootmem(__pa(initrd_start)-__MEMORY_START, + INITRD_SIZE); } #endif diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile index 934c84744..5f7d68755 100644 --- a/arch/sh/lib/Makefile +++ b/arch/sh/lib/Makefile @@ -6,7 +6,7 @@ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o L_TARGET = lib.a -L_OBJS = delay.o memcpy.o memset.o memmove.o old-checksum.o \ +L_OBJS = delay.o memcpy.o memset.o memmove.o memchr.o old-checksum.o \ checksum.o include $(TOPDIR)/Rules.make diff --git a/arch/sh/lib/memchr.S b/arch/sh/lib/memchr.S new file mode 100644 index 000000000..d5f9ba2e3 --- /dev/null +++ b/arch/sh/lib/memchr.S @@ -0,0 +1,26 @@ +/* $Id: memchr.S,v 1.1 1999/10/17 11:32:38 gniibe Exp $ + * + * "memchr" implementation of SuperH + * + * Copyright (C) 1999 Niibe Yutaka + * + */ + +/* + * void *memchr(const void *s, int c, size_t n); + */ + +#include <linux/linkage.h> +ENTRY(memchr) + tst r6,r6 + bt/s 2f + exts.b r5,r5 +1: mov.b @r4,r1 + cmp/eq r1,r5 + bt/s 3f + dt r6 + bf/s 1b + add #1,r4 +2: mov #0,r4 +3: rts + mov r4,r0 diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 4c602a385..2dc194a77 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -24,6 +24,7 @@ #ifdef CONFIG_BLK_DEV_INITRD #include <linux/blk.h> #endif +#include <linux/bootmem.h> #include <asm/processor.h> #include <asm/system.h> @@ -37,21 +38,53 @@ */ unsigned long mmu_context_cache; -static unsigned long totalram = 0; +static unsigned long totalram_pages = 0; +static unsigned long totalhigh_pages = 0; extern void show_net_buffers(void); extern unsigned long init_smp_mappings(unsigned long); -void __bad_pte_kernel(pmd_t *pmd) +/* + * 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 an 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. + */ + +unsigned long empty_bad_page[1024]; +pte_t empty_bad_pte_table[PTRS_PER_PTE]; +extern unsigned long empty_zero_page[1024]; + +static pte_t * get_bad_pte_table(void) +{ + pte_t v; + int i; + + v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); + + for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) + empty_bad_pte_table[i] = v; + + return empty_bad_pte_table; +} + +void __handle_bad_pmd(pmd_t *pmd) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE); + pmd_ERROR(*pmd); + pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); } -void __bad_pte(pmd_t *pmd) +void __handle_bad_pmd_kernel(pmd_t *pmd) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); + pmd_ERROR(*pmd); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); } pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) @@ -61,16 +94,16 @@ pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) pte = (pte_t *) __get_free_page(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - clear_page((unsigned long)pte); + clear_page(pte); pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); return pte + offset; } - pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); return NULL; } free_page((unsigned long)pte); if (pmd_bad(*pmd)) { - __bad_pte_kernel(pmd); + __handle_bad_pmd_kernel(pmd); return NULL; } return (pte_t *) pmd_page(*pmd) + offset; @@ -83,19 +116,19 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) pte = (unsigned long) __get_free_page(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - clear_page(pte); + clear_page((void *)pte); pmd_val(*pmd) = _PAGE_TABLE + __pa(pte); - return (pte_t *)(pte + offset); + return (pte_t *)pte + offset; } - pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); + pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); return NULL; } free_page(pte); if (pmd_bad(*pmd)) { - __bad_pte(pmd); + __handle_bad_pmd(pmd); return NULL; } - return (pte_t *) (pmd_page(*pmd) + offset); + return (pte_t *) pmd_page(*pmd) + offset; } int do_check_pgt_cache(int low, int high) @@ -114,37 +147,6 @@ int do_check_pgt_cache(int low, int high) return freed; } -/* - * 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 an 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 unsigned long empty_bad_page_table[PAGE_SIZE]; - unsigned long page = (unsigned long)empty_bad_page_table; - - clear_page(page); - return (pte_t *)empty_bad_page_table; -} - -pte_t __bad_page(void) -{ - extern char empty_bad_page[PAGE_SIZE]; - unsigned long page = (unsigned long)empty_bad_page; - - clear_page(page); - return pte_mkdirty(mk_pte(page, PAGE_SHARED)); -} - void show_mem(void) { int i,free = 0,total = 0,reserved = 0; @@ -170,13 +172,12 @@ void show_mem(void) printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); + show_buffers(); #ifdef CONFIG_NET show_net_buffers(); #endif } -extern unsigned long free_area_init(unsigned long, unsigned long); - /* References to section boundaries */ extern char _text, _etext, _edata, __bss_start, _end; @@ -190,13 +191,10 @@ pgd_t swapper_pg_dir[1024]; * 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 __init -paging_init(unsigned long start_mem, unsigned long end_mem) +void __init paging_init(void) { pgd_t * pg_dir; - start_mem = PAGE_ALIGN(start_mem); - /* We don't need kernel mapping as hardware support that. */ pg_dir = swapper_pg_dir; @@ -209,61 +207,25 @@ paging_init(unsigned long start_mem, unsigned long end_mem) mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK); - return free_area_init(start_mem, end_mem); + free_area_init(max_low_pfn); } -unsigned long empty_bad_page[1024]; -unsigned long empty_bad_page_table[1024]; -extern unsigned long empty_zero_page[1024]; - -void __init mem_init(unsigned long start_mem, unsigned long end_mem) +void __init mem_init(void) { int codepages = 0; int reservedpages = 0; int datapages = 0; int initpages = 0; - unsigned long tmp; - end_mem &= PAGE_MASK; - high_memory = (void *) end_mem; - max_mapnr = num_physpages = MAP_NR(end_mem); + max_mapnr = num_physpages = max_low_pfn; + high_memory = (void *) ((unsigned long)__va(max_low_pfn * PAGE_SIZE)+__MEMORY_START); /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); - /* Mark (clear "reserved" bit) usable pages in the mem_map[] */ - /* Note that all are marked reserved already. */ - tmp = start_mem = PAGE_ALIGN(start_mem); - while (tmp < end_mem) { - clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags); - clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); - tmp += PAGE_SIZE; - } + /* this will put all low memory onto the freelists */ + totalram_pages += free_all_bootmem(); - for (tmp = PAGE_OFFSET; tmp < end_mem; tmp += PAGE_SIZE) { - if (PageReserved(mem_map+MAP_NR(tmp))) { - if (tmp >= (unsigned long) &_text && tmp < (unsigned long) &_edata) { - if (tmp < (unsigned long) &_etext) - codepages++; - else - datapages++; - } else if (tmp >= (unsigned long) &__init_begin - && tmp < (unsigned long) &__init_end) - initpages++; - else if (tmp >= (unsigned long) &__bss_start - && tmp < (unsigned long) start_mem) - datapages++; - else - reservedpages++; - 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)) -#endif - free_page(tmp); - } printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), @@ -279,19 +241,22 @@ void free_initmem(void) addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); + ClearPageReserved(mem_map + MAP_NR(addr)); set_page_count(mem_map+MAP_NR(addr), 1); free_page(addr); - totalram += PAGE_SIZE; + totalram_pages++; } printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } void si_meminfo(struct sysinfo *val) { - val->totalram = totalram; + val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = nr_free_pages << PAGE_SHIFT; - val->bufferram = atomic_read(&buffermem); + val->freeram = nr_free_pages; + val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = totalhigh_pages; + val->freehigh = nr_free_highpages; + val->mem_unit = PAGE_SIZE; return; } |