Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nios2: Kernel booting and initialization

This patch adds the kernel booting and the initial setup code.

Signed-off-by: Ley Foon Tan <lftan@altera.com>

+551
+120
arch/nios2/include/asm/entry.h
··· 1 + /* 2 + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> 3 + * Copyright (C) 2004 Microtronix Datacom Ltd. 4 + * 5 + * This file is subject to the terms and conditions of the GNU General Public 6 + * License. See the file "COPYING" in the main directory of this archive 7 + * for more details. 8 + */ 9 + 10 + #ifndef _ASM_NIOS2_ENTRY_H 11 + #define _ASM_NIOS2_ENTRY_H 12 + 13 + #ifdef __ASSEMBLY__ 14 + 15 + #include <asm/processor.h> 16 + #include <asm/registers.h> 17 + #include <asm/asm-offsets.h> 18 + 19 + /* 20 + * Standard Nios2 interrupt entry and exit macros. 21 + * Must be called with interrupts disabled. 22 + */ 23 + .macro SAVE_ALL 24 + rdctl r24, estatus 25 + andi r24, r24, ESTATUS_EU 26 + beq r24, r0, 1f /* In supervisor mode, already on kernel stack */ 27 + 28 + movia r24, _current_thread /* Switch to current kernel stack */ 29 + ldw r24, 0(r24) /* using the thread_info */ 30 + addi r24, r24, THREAD_SIZE-PT_REGS_SIZE 31 + stw sp, PT_SP(r24) /* Save user stack before changing */ 32 + mov sp, r24 33 + br 2f 34 + 35 + 1 : mov r24, sp 36 + addi sp, sp, -PT_REGS_SIZE /* Backup the kernel stack pointer */ 37 + stw r24, PT_SP(sp) 38 + 2 : stw r1, PT_R1(sp) 39 + stw r2, PT_R2(sp) 40 + stw r3, PT_R3(sp) 41 + stw r4, PT_R4(sp) 42 + stw r5, PT_R5(sp) 43 + stw r6, PT_R6(sp) 44 + stw r7, PT_R7(sp) 45 + stw r8, PT_R8(sp) 46 + stw r9, PT_R9(sp) 47 + stw r10, PT_R10(sp) 48 + stw r11, PT_R11(sp) 49 + stw r12, PT_R12(sp) 50 + stw r13, PT_R13(sp) 51 + stw r14, PT_R14(sp) 52 + stw r15, PT_R15(sp) 53 + stw r2, PT_ORIG_R2(sp) 54 + stw r7, PT_ORIG_R7(sp) 55 + 56 + stw ra, PT_RA(sp) 57 + stw fp, PT_FP(sp) 58 + stw gp, PT_GP(sp) 59 + rdctl r24, estatus 60 + stw r24, PT_ESTATUS(sp) 61 + stw ea, PT_EA(sp) 62 + .endm 63 + 64 + .macro RESTORE_ALL 65 + ldw r1, PT_R1(sp) /* Restore registers */ 66 + ldw r2, PT_R2(sp) 67 + ldw r3, PT_R3(sp) 68 + ldw r4, PT_R4(sp) 69 + ldw r5, PT_R5(sp) 70 + ldw r6, PT_R6(sp) 71 + ldw r7, PT_R7(sp) 72 + ldw r8, PT_R8(sp) 73 + ldw r9, PT_R9(sp) 74 + ldw r10, PT_R10(sp) 75 + ldw r11, PT_R11(sp) 76 + ldw r12, PT_R12(sp) 77 + ldw r13, PT_R13(sp) 78 + ldw r14, PT_R14(sp) 79 + ldw r15, PT_R15(sp) 80 + ldw ra, PT_RA(sp) 81 + ldw fp, PT_FP(sp) 82 + ldw gp, PT_GP(sp) 83 + ldw r24, PT_ESTATUS(sp) 84 + wrctl estatus, r24 85 + ldw ea, PT_EA(sp) 86 + ldw sp, PT_SP(sp) /* Restore sp last */ 87 + .endm 88 + 89 + .macro SAVE_SWITCH_STACK 90 + addi sp, sp, -SWITCH_STACK_SIZE 91 + stw r16, SW_R16(sp) 92 + stw r17, SW_R17(sp) 93 + stw r18, SW_R18(sp) 94 + stw r19, SW_R19(sp) 95 + stw r20, SW_R20(sp) 96 + stw r21, SW_R21(sp) 97 + stw r22, SW_R22(sp) 98 + stw r23, SW_R23(sp) 99 + stw fp, SW_FP(sp) 100 + stw gp, SW_GP(sp) 101 + stw ra, SW_RA(sp) 102 + .endm 103 + 104 + .macro RESTORE_SWITCH_STACK 105 + ldw r16, SW_R16(sp) 106 + ldw r17, SW_R17(sp) 107 + ldw r18, SW_R18(sp) 108 + ldw r19, SW_R19(sp) 109 + ldw r20, SW_R20(sp) 110 + ldw r21, SW_R21(sp) 111 + ldw r22, SW_R22(sp) 112 + ldw r23, SW_R23(sp) 113 + ldw fp, SW_FP(sp) 114 + ldw gp, SW_GP(sp) 115 + ldw ra, SW_RA(sp) 116 + addi sp, sp, SWITCH_STACK_SIZE 117 + .endm 118 + 119 + #endif /* __ASSEMBLY__ */ 120 + #endif /* _ASM_NIOS2_ENTRY_H */
+38
arch/nios2/include/asm/setup.h
··· 1 + /* 2 + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License as published by 6 + * the Free Software Foundation; either version 2 of the License, or 7 + * (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 + * 17 + */ 18 + 19 + #ifndef _ASM_NIOS2_SETUP_H 20 + #define _ASM_NIOS2_SETUP_H 21 + 22 + #include <asm-generic/setup.h> 23 + 24 + #ifndef __ASSEMBLY__ 25 + #ifdef __KERNEL__ 26 + 27 + extern char exception_handler_hook[]; 28 + extern char fast_handler[]; 29 + extern char fast_handler_end[]; 30 + 31 + extern void pagetable_init(void); 32 + 33 + extern void setup_early_printk(void); 34 + 35 + #endif/* __KERNEL__ */ 36 + #endif /* __ASSEMBLY__ */ 37 + 38 + #endif /* _ASM_NIOS2_SETUP_H */
+175
arch/nios2/kernel/head.S
··· 1 + /* 2 + * Copyright (C) 2009 Wind River Systems Inc 3 + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com 4 + * Copyright (C) 2004 Microtronix Datacom Ltd 5 + * Copyright (C) 2001 Vic Phillips, Microtronix Datacom Ltd. 6 + * 7 + * Based on head.S for Altera's Excalibur development board with nios processor 8 + * 9 + * Based on the following from the Excalibur sdk distribution: 10 + * NA_MemoryMap.s, NR_JumpToStart.s, NR_Setup.s, NR_CWPManager.s 11 + * 12 + * This file is subject to the terms and conditions of the GNU General Public 13 + * License. See the file "COPYING" in the main directory of this archive 14 + * for more details. 15 + */ 16 + 17 + #include <linux/init.h> 18 + #include <linux/linkage.h> 19 + #include <asm/thread_info.h> 20 + #include <asm/processor.h> 21 + #include <asm/cache.h> 22 + #include <asm/page.h> 23 + #include <asm/asm-offsets.h> 24 + #include <asm/asm-macros.h> 25 + 26 + /* 27 + * ZERO_PAGE is a special page that is used for zero-initialized 28 + * data and COW. 29 + */ 30 + .data 31 + .global empty_zero_page 32 + .align 12 33 + empty_zero_page: 34 + .space PAGE_SIZE 35 + 36 + /* 37 + * This global variable is used as an extension to the nios' 38 + * STATUS register to emulate a user/supervisor mode. 39 + */ 40 + .data 41 + .align 2 42 + .set noat 43 + 44 + .global _current_thread 45 + _current_thread: 46 + .long 0 47 + /* 48 + * Input(s): passed from u-boot 49 + * r4 - Optional pointer to a board information structure. 50 + * r5 - Optional pointer to the physical starting address of the init RAM 51 + * disk. 52 + * r6 - Optional pointer to the physical ending address of the init RAM 53 + * disk. 54 + * r7 - Optional pointer to the physical starting address of any kernel 55 + * command-line parameters. 56 + */ 57 + 58 + /* 59 + * First executable code - detected and jumped to by the ROM bootstrap 60 + * if the code resides in flash (looks for "Nios" at offset 0x0c from 61 + * the potential executable image). 62 + */ 63 + __HEAD 64 + ENTRY(_start) 65 + wrctl status, r0 /* Disable interrupts */ 66 + 67 + /* Initialize all cache lines within the instruction cache */ 68 + movia r1, NIOS2_ICACHE_SIZE 69 + movui r2, NIOS2_ICACHE_LINE_SIZE 70 + 71 + icache_init: 72 + initi r1 73 + sub r1, r1, r2 74 + bgt r1, r0, icache_init 75 + br 1f 76 + 77 + /* 78 + * This is the default location for the exception handler. Code in jump 79 + * to our handler 80 + */ 81 + ENTRY(exception_handler_hook) 82 + movia r24, inthandler 83 + jmp r24 84 + 85 + ENTRY(fast_handler) 86 + nextpc et 87 + helper: 88 + stw r3, r3save - helper(et) 89 + 90 + rdctl r3 , pteaddr 91 + srli r3, r3, 12 92 + slli r3, r3, 2 93 + movia et, pgd_current 94 + 95 + ldw et, 0(et) 96 + add r3, et, r3 97 + ldw et, 0(r3) 98 + 99 + rdctl r3, pteaddr 100 + andi r3, r3, 0xfff 101 + add et, r3, et 102 + ldw et, 0(et) 103 + wrctl tlbacc, et 104 + nextpc et 105 + helper2: 106 + ldw r3, r3save - helper2(et) 107 + subi ea, ea, 4 108 + eret 109 + r3save: 110 + .word 0x0 111 + ENTRY(fast_handler_end) 112 + 113 + 1: 114 + /* 115 + * After the instruction cache is initialized, the data cache must 116 + * also be initialized. 117 + */ 118 + movia r1, NIOS2_DCACHE_SIZE 119 + movui r2, NIOS2_DCACHE_LINE_SIZE 120 + 121 + dcache_init: 122 + initd 0(r1) 123 + sub r1, r1, r2 124 + bgt r1, r0, dcache_init 125 + 126 + nextpc r1 /* Find out where we are */ 127 + chkadr: 128 + movia r2, chkadr 129 + beq r1, r2,finish_move /* We are running in RAM done */ 130 + addi r1, r1,(_start - chkadr) /* Source */ 131 + movia r2, _start /* Destination */ 132 + movia r3, __bss_start /* End of copy */ 133 + 134 + loop_move: /* r1: src, r2: dest, r3: last dest */ 135 + ldw r8, 0(r1) /* load a word from [r1] */ 136 + stw r8, 0(r2) /* store a word to dest [r2] */ 137 + flushd 0(r2) /* Flush cache for safety */ 138 + addi r1, r1, 4 /* inc the src addr */ 139 + addi r2, r2, 4 /* inc the dest addr */ 140 + blt r2, r3, loop_move 141 + 142 + movia r1, finish_move /* VMA(_start)->l1 */ 143 + jmp r1 /* jmp to _start */ 144 + 145 + finish_move: 146 + 147 + /* Mask off all possible interrupts */ 148 + wrctl ienable, r0 149 + 150 + /* Clear .bss */ 151 + movia r2, __bss_start 152 + movia r1, __bss_stop 153 + 1: 154 + stb r0, 0(r2) 155 + addi r2, r2, 1 156 + bne r1, r2, 1b 157 + 158 + movia r1, init_thread_union /* set stack at top of the task union */ 159 + addi sp, r1, THREAD_SIZE 160 + movia r2, _current_thread /* Remember current thread */ 161 + stw r1, 0(r2) 162 + 163 + movia r1, nios2_boot_init /* save args r4-r7 passed from u-boot */ 164 + callr r1 165 + 166 + movia r1, start_kernel /* call start_kernel as a subroutine */ 167 + callr r1 168 + 169 + /* If we return from start_kernel, break to the oci debugger and 170 + * buggered we are. 171 + */ 172 + break 173 + 174 + /* End of startup code */ 175 + .set at
+218
arch/nios2/kernel/setup.c
··· 1 + /* 2 + * Nios2-specific parts of system setup 3 + * 4 + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> 5 + * Copyright (C) 2004 Microtronix Datacom Ltd. 6 + * Copyright (C) 2001 Vic Phillips <vic@microtronix.com> 7 + * 8 + * This file is subject to the terms and conditions of the GNU General Public 9 + * License. See the file "COPYING" in the main directory of this archive 10 + * for more details. 11 + */ 12 + 13 + #include <linux/export.h> 14 + #include <linux/kernel.h> 15 + #include <linux/mm.h> 16 + #include <linux/sched.h> 17 + #include <linux/console.h> 18 + #include <linux/bootmem.h> 19 + #include <linux/initrd.h> 20 + #include <linux/of_fdt.h> 21 + 22 + #include <asm/mmu_context.h> 23 + #include <asm/sections.h> 24 + #include <asm/setup.h> 25 + #include <asm/cpuinfo.h> 26 + 27 + unsigned long memory_start; 28 + EXPORT_SYMBOL(memory_start); 29 + 30 + unsigned long memory_end; 31 + EXPORT_SYMBOL(memory_end); 32 + 33 + unsigned long memory_size; 34 + 35 + static struct pt_regs fake_regs = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36 + 0, 0, 0, 0, 0, 0, 37 + 0}; 38 + 39 + /* Copy a short hook instruction sequence to the exception address */ 40 + static inline void copy_exception_handler(unsigned int addr) 41 + { 42 + unsigned int start = (unsigned int) exception_handler_hook; 43 + volatile unsigned int tmp = 0; 44 + 45 + if (start == addr) { 46 + /* The CPU exception address already points to the handler. */ 47 + return; 48 + } 49 + 50 + __asm__ __volatile__ ( 51 + "ldw %2,0(%0)\n" 52 + "stw %2,0(%1)\n" 53 + "ldw %2,4(%0)\n" 54 + "stw %2,4(%1)\n" 55 + "ldw %2,8(%0)\n" 56 + "stw %2,8(%1)\n" 57 + "flushd 0(%1)\n" 58 + "flushd 4(%1)\n" 59 + "flushd 8(%1)\n" 60 + "flushi %1\n" 61 + "addi %1,%1,4\n" 62 + "flushi %1\n" 63 + "addi %1,%1,4\n" 64 + "flushi %1\n" 65 + "flushp\n" 66 + : /* no output registers */ 67 + : "r" (start), "r" (addr), "r" (tmp) 68 + : "memory" 69 + ); 70 + } 71 + 72 + /* Copy the fast TLB miss handler */ 73 + static inline void copy_fast_tlb_miss_handler(unsigned int addr) 74 + { 75 + unsigned int start = (unsigned int) fast_handler; 76 + unsigned int end = (unsigned int) fast_handler_end; 77 + volatile unsigned int tmp = 0; 78 + 79 + __asm__ __volatile__ ( 80 + "1:\n" 81 + " ldw %3,0(%0)\n" 82 + " stw %3,0(%1)\n" 83 + " flushd 0(%1)\n" 84 + " flushi %1\n" 85 + " flushp\n" 86 + " addi %0,%0,4\n" 87 + " addi %1,%1,4\n" 88 + " bne %0,%2,1b\n" 89 + : /* no output registers */ 90 + : "r" (start), "r" (addr), "r" (end), "r" (tmp) 91 + : "memory" 92 + ); 93 + } 94 + 95 + /* 96 + * save args passed from u-boot, called from head.S 97 + * 98 + * @r4: NIOS magic 99 + * @r5: initrd start 100 + * @r6: initrd end or fdt 101 + * @r7: kernel command line 102 + */ 103 + asmlinkage void __init nios2_boot_init(unsigned r4, unsigned r5, unsigned r6, 104 + unsigned r7) 105 + { 106 + unsigned dtb_passed = 0; 107 + char cmdline_passed[COMMAND_LINE_SIZE] = { 0, }; 108 + 109 + #if defined(CONFIG_NIOS2_PASS_CMDLINE) 110 + if (r4 == 0x534f494e) { /* r4 is magic NIOS */ 111 + #if defined(CONFIG_BLK_DEV_INITRD) 112 + if (r5) { /* initramfs */ 113 + initrd_start = r5; 114 + initrd_end = r6; 115 + } 116 + #endif /* CONFIG_BLK_DEV_INITRD */ 117 + dtb_passed = r6; 118 + 119 + if (r7) 120 + strncpy(cmdline_passed, (char *)r7, COMMAND_LINE_SIZE); 121 + } 122 + #endif 123 + 124 + early_init_devtree((void *)dtb_passed); 125 + 126 + #ifndef CONFIG_CMDLINE_FORCE 127 + if (cmdline_passed[0]) 128 + strncpy(boot_command_line, cmdline_passed, COMMAND_LINE_SIZE); 129 + #ifdef CONFIG_NIOS2_CMDLINE_IGNORE_DTB 130 + else 131 + strncpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 132 + #endif 133 + #endif 134 + } 135 + 136 + void __init setup_arch(char **cmdline_p) 137 + { 138 + int bootmap_size; 139 + 140 + console_verbose(); 141 + 142 + memory_start = PAGE_ALIGN((unsigned long)__pa(_end)); 143 + memory_end = (unsigned long) CONFIG_NIOS2_MEM_BASE + memory_size; 144 + 145 + init_mm.start_code = (unsigned long) _stext; 146 + init_mm.end_code = (unsigned long) _etext; 147 + init_mm.end_data = (unsigned long) _edata; 148 + init_mm.brk = (unsigned long) _end; 149 + init_task.thread.kregs = &fake_regs; 150 + 151 + /* Keep a copy of command line */ 152 + *cmdline_p = boot_command_line; 153 + 154 + min_low_pfn = PFN_UP(memory_start); 155 + max_low_pfn = PFN_DOWN(memory_end); 156 + max_mapnr = max_low_pfn; 157 + 158 + /* 159 + * give all the memory to the bootmap allocator, tell it to put the 160 + * boot mem_map at the start of memory 161 + */ 162 + pr_debug("init_bootmem_node(?,%#lx, %#x, %#lx)\n", 163 + min_low_pfn, PFN_DOWN(PHYS_OFFSET), max_low_pfn); 164 + bootmap_size = init_bootmem_node(NODE_DATA(0), 165 + min_low_pfn, PFN_DOWN(PHYS_OFFSET), 166 + max_low_pfn); 167 + 168 + /* 169 + * free the usable memory, we have to make sure we do not free 170 + * the bootmem bitmap so we then reserve it after freeing it :-) 171 + */ 172 + pr_debug("free_bootmem(%#lx, %#lx)\n", 173 + memory_start, memory_end - memory_start); 174 + free_bootmem(memory_start, memory_end - memory_start); 175 + 176 + /* 177 + * Reserve the bootmem bitmap itself as well. We do this in two 178 + * steps (first step was init_bootmem()) because this catches 179 + * the (very unlikely) case of us accidentally initializing the 180 + * bootmem allocator with an invalid RAM area. 181 + * 182 + * Arguments are start, size 183 + */ 184 + pr_debug("reserve_bootmem(%#lx, %#x)\n", memory_start, bootmap_size); 185 + reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT); 186 + 187 + #ifdef CONFIG_BLK_DEV_INITRD 188 + if (initrd_start) { 189 + reserve_bootmem(virt_to_phys((void *)initrd_start), 190 + initrd_end - initrd_start, BOOTMEM_DEFAULT); 191 + } 192 + #endif /* CONFIG_BLK_DEV_INITRD */ 193 + 194 + unflatten_and_copy_device_tree(); 195 + 196 + setup_cpuinfo(); 197 + 198 + copy_exception_handler(cpuinfo.exception_addr); 199 + 200 + mmu_init(); 201 + 202 + copy_fast_tlb_miss_handler(cpuinfo.fast_tlb_miss_exc_addr); 203 + 204 + /* 205 + * Initialize MMU context handling here because data from cpuinfo is 206 + * needed for this. 207 + */ 208 + mmu_context_init(); 209 + 210 + /* 211 + * get kmalloc into gear 212 + */ 213 + paging_init(); 214 + 215 + #if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) 216 + conswitchp = &dummy_con; 217 + #endif 218 + }